1: <?php
2: /**
3: * This file contains the implementation of the interface IRequestHandler
4: * in the class JsonRequestHandler for handling the JSON API requests.
5: *
6: * @package System
7: *
8: * @author Oleg Schildt
9: */
10:
11: namespace SmartFactory;
12:
13: use \SmartFactory\Interfaces\IErrorHandler;
14:
15: /**
16: * Class for handling the JSON API requests.
17: *
18: * The user should derive from this class and implement the methods with the names
19: * of the API actions.
20: *
21: * URL: http://smartfactorydev.loc/api/login/
22: *
23: * Action: login
24: *
25: * ```php
26: * function login()
27: * {
28: * if (empty($this->request_data["login"]) || empty($this->request_data["password"]) ||
29: * $this->request_data["login"] != "admin" || $this->request_data["password"] != "qwerty") {
30: * throw new SmartException("Wrong login or password!", "wrong_login");
31: * }
32: *
33: * $this->response_data["welcome_msg"] = "Welcome, admin!";
34: * }
35: * ```
36: *
37: * @author Oleg Schildt
38: */
39: abstract class JsonRequestHandler extends RequestHandler
40: {
41: /**
42: * Internal variable for storing the request data.
43: *
44: * @var array
45: *
46: * @author Oleg Schildt
47: */
48: protected array $request_data = [];
49:
50: /**
51: * Internal variable for storing the response data.
52: *
53: * @var array
54: *
55: * @author Oleg Schildt
56: */
57: protected array $response_data = [];
58:
59: /**
60: * This is an auxiliary function for sending the response in JSON format.
61: *
62: * It sends the collected response data and the response headers. The header
63: * "Content-type: application/json; charset=UTF-8" ist sent automatically.
64: *
65: * @return void
66: *
67: * @throws SmartException
68: * It might throw exceptions in the case of any errors.
69: *
70: * @author Oleg Schildt
71: */
72: protected function sendResponse(): void
73: {
74: $this->addResponseHeader("Content-type", "application/json; charset=UTF-8");
75:
76: if (!empty($this->response_headers)) {
77: if (is_array($this->response_headers)) {
78: foreach ($this->response_headers as $header => $value) {
79: header($header . ": " . $value);
80: }
81: }
82: }
83:
84: $this->addMessagesToResponse();
85:
86: if (empty($this->response_data)) {
87: echo json_encode($this->response_data, JSON_FORCE_OBJECT | JSON_PRETTY_PRINT);
88: } else {
89: echo json_encode($this->response_data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
90: }
91: } // sendResponse
92:
93: /**
94: * This is an auxiliary function for parsing the incoming JSON data.
95: *
96: * It validates the content type 'application/json' and takes the data from RAWDATA.
97: *
98: * @return void
99: *
100: * @throws \Exception|SmartException
101: * It might throw an exception if the content type oк JSON data is invalid.
102: *
103: * @author Oleg Schildt
104: */
105: protected function parseInput(): void
106: {
107: try {
108: $content_type = get_header("Content-Type");
109:
110: if (empty($content_type)) {
111: throw new SmartException("Content type header 'Content-Type' is missing, expected 'application/json; charset=UTF-8'!", SmartException::ERR_CODE_INVALID_CONTENT_TYPE);
112: }
113:
114: if (!preg_match("/application\/json.*charset=UTF-8/i", $content_type)) {
115: throw new SmartException(sprintf("Content type 'application/json; charset=UTF-8' is expected, got '%s'!", $content_type), SmartException::ERR_CODE_INVALID_CONTENT_TYPE);
116: }
117:
118: $json = trim(file_get_contents("php://input"));
119:
120: if (empty($json)) {
121: throw new SmartException("The request JSON is empty!", SmartException::ERR_CODE_MISSING_REQUEST_DATA);
122: }
123:
124: $json = json_decode($json, true);
125:
126: if (empty($json) && !is_array($json)) {
127: throw new SmartException(json_last_error_msg(), SmartException::ERR_CODE_JSON_PARSE_ERROR);
128: }
129:
130: $this->request_data = array_merge($this->request_data, $json);
131: } catch (SmartException $ex) {
132: throw $ex;
133: } catch (\Throwable $ex) {
134: singleton(IErrorHandler::class)->handleException($ex, E_USER_ERROR);
135:
136: throw new SmartException($ex->getMessage(), SmartException::ERR_CODE_JSON_PARSE_ERROR);
137: }
138: } // parseInput
139: } // JsonRequestHandler