Completed
Push — master ( 518d41...c63fee )
by Thomas
9s
created

ModuleEntryPoint   A

Complexity

Total Complexity 24

Size/Duplication

Total Lines 121
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 9

Test Coverage

Coverage 86.11%

Importance

Changes 11
Bugs 1 Features 1
Metric Value
wmc 24
c 11
b 1
f 1
lcom 1
cbo 9
dl 0
loc 121
ccs 62
cts 72
cp 0.8611
rs 10

12 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 3 1
A getRequestBody() 0 3 1
A outputResponse() 0 4 1
A buildRequestDeserializer() 0 4 1
A buildResponseSerializer() 0 4 1
A outputHttpException() 0 4 1
A exec() 0 12 3
A filterRequestMethod() 0 11 4
A getRequest() 0 8 2
B cleanResponses() 0 26 5
A serializeResponse() 0 7 2
A setHttpResponseCode() 0 7 2
1
<?php
2
3
namespace PPP\Module;
4
5
use Deserializers\Exceptions\DeserializationException;
6
use Exception;
7
use PPP\DataModel\DeserializerFactory;
8
use PPP\DataModel\SerializerFactory;
9
use PPP\Module\DataModel\Deserializers\ModuleRequestDeserializer;
10
use PPP\Module\DataModel\ModuleRequest;
11
use PPP\Module\DataModel\ModuleResponse;
12
use PPP\Module\DataModel\Serializers\ModuleResponseSerializer;
13
14
/**
15
 * Entry point for Modules
16
 *
17
 * @licence MIT
18
 * @author Thomas Pellissier Tanon
19
 */
20
class ModuleEntryPoint {
21
22
	/**
23
	 * @var RequestHandler
24
	 */
25
	private $requestHandler;
26
27
	/**
28
	 * @param RequestHandler $requestHandler
29
	 */
30 7
	public function __construct(RequestHandler $requestHandler) {
31 7
		$this->requestHandler = $requestHandler;
32 7
	}
33
34
	/**
35
	 * Main function
36
	 */
37 7
	public function exec() {
38
		try {
39 7
			$this->filterRequestMethod();
40 7
			$request = $this->getRequest();
41 6
			$responses = $this->requestHandler->buildResponse($request);
42 5
			$this->outputResponse($this->serializeResponse($this->cleanResponses($responses, $request)));
43 7
		} catch(HttpException $e) {
44 1
			$this->outputHttpException($e);
45 2
		} catch(Exception $e) {
46 1
			$this->outputHttpException(new HttpException($e->getMessage(), 500, $e));
47
		}
48 7
	}
49
50 7
	private function filterRequestMethod() {
0 ignored issues
show
Coding Style introduced by
filterRequestMethod uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
51 7
		if(!array_key_exists('REQUEST_METHOD', $_SERVER)) {
52 7
			return;
53
		}
54
		if($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
55
			exit();
0 ignored issues
show
Coding Style Compatibility introduced by
The method filterRequestMethod() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
56
		}
57
		if($_SERVER['REQUEST_METHOD'] !== 'POST') {
58
			new HttpException('Bad request method: ' . $_SERVER['REQUEST_METHOD'], 405);
59
		}
60
	}
61
62
	/**
63
	 * @return ModuleRequest
64
	 */
65 7
	private function getRequest() {
66 7
		$requestJson = json_decode($this->getRequestBody(), true);
67
		try {
68 7
			return $this->buildRequestDeserializer()->deserialize($requestJson);
69 1
		} catch(DeserializationException $e) {
70 1
			throw new HttpException($e->getMessage(), 400, $e);
71
		}
72
	}
73
74
	public function getRequestBody() {
75
		return file_get_contents("php://input");
76
	}
77
78 5
	private function cleanResponses(array $responses, ModuleRequest $request) {
79 5
		$cleanedResponses = array();
80
81
		/** @var ModuleResponse $response */
82 5
		foreach($responses as $response) {
83 4
			if($request->getSentenceTree()->equals($response->getSentenceTree())) {
84
				continue;
85
			}
86
87
			/** @var ModuleResponse $existingResponse */
88 4
			foreach($cleanedResponses as $existingResponse) {
89 1
				if($existingResponse->getSentenceTree()->equals($response->getSentenceTree())) {
90 1
					continue 2;
91
				}
92 4
			}
93
94 4
			$cleanedResponses[] = new ModuleResponse(
95 4
				$response->getLanguageCode(),
96 4
				$response->getSentenceTree(),
97 4
				$response->getMeasures() + $request->getMeasures(),
98 4
				$response->getTrace()
99 4
			);
100 5
		}
101
102 5
		return $cleanedResponses;
103
	}
104
105 5
	private function outputResponse($serialization) {
106 5
		@header('Content-type: application/json');
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
107 5
		echo json_encode($serialization);
108 5
	}
109
110 5
	private function serializeResponse(array $responses) {
111 5
		$serialization = array();
112 5
		foreach($responses as $response) {
113 4
			$serialization[] = $this->buildResponseSerializer()->serialize($response);
114 5
		}
115 5
		return $serialization;
116
	}
117
118 7
	private function buildRequestDeserializer() {
119 7
		$deserializerFactory = new DeserializerFactory($this->requestHandler->getCustomResourceNodeDeserializers());
120 7
		return new ModuleRequestDeserializer($deserializerFactory->newNodeDeserializer());
121
	}
122
123 4
	private function buildResponseSerializer() {
124 4
		$serializerFactory = new SerializerFactory($this->requestHandler->getCustomResourceNodeSerializers());
125 4
		return new ModuleResponseSerializer($serializerFactory->newNodeSerializer());
126
	}
127
128 2
	private function outputHttpException(HttpException $exception) {
129 2
		$this->setHttpResponseCode($exception->getCode());
130 2
		echo $exception->getMessage();
131 2
	}
132
133 2
	private function setHttpResponseCode($code) {
134 2
		if(function_exists('http_response_code')) {
135 2
			@http_response_code($code);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
136 2
		} else {
137
			@header('X-PHP-Response-Code: '. $code, true, $code);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
138
		}
139 2
	}
140
}
141