Elgg  Version master
Service.php
Go to the documentation of this file.
1 <?php
2 
3 namespace Elgg\Ajax;
4 
12 
19 class Service {
20 
21  protected bool $response_sent = false;
22 
23  protected array $allowed_views = [];
24 
33  public function __construct(
34  protected EventsService $events,
35  protected SystemMessagesService $msgs,
36  protected Request $request,
37  protected ESMService $esm
38  ) {
39  $message_filter = [$this, 'prepareResponse'];
40  $this->events->registerHandler(AjaxResponse::RESPONSE_EVENT, 'all', $message_filter, 999);
41  }
42 
48  public function isAjax2Request(): bool {
49  $version = $this->request->headers->get('X-Elgg-Ajax-API');
50  return ($version === '2');
51  }
52 
62  public function isReady(): bool {
63  return !$this->response_sent && $this->isAjax2Request();
64  }
65 
73  public function decodeJson($string) {
74  if (!is_string($string)) {
75  return $string;
76  }
77 
78  $object = json_decode($string);
79  return ($object === null) ? $string : $object;
80  }
81 
91  public function respondFromOutput($output, string $event_type = '', bool $try_decode = true) {
92  if ($try_decode) {
93  $output = $this->decodeJson($output);
94  }
95 
96  $api_response = new Response();
97  if (is_object($output) && isset($output->value)) {
98  $api_response->setData($output);
99  } elseif (is_array($output) && isset($output['value'])) {
100  $api_response->setData((object) $output);
101  } else {
102  $api_response->setData((object) ['value' => $output]);
103  }
104 
105  $api_response = $this->filterApiResponse($api_response, $event_type);
106  $response = $this->buildHttpResponse($api_response);
107 
108  $this->response_sent = true;
109  return _elgg_services()->responseFactory->send($response);
110  }
111 
120  public function respondFromApiResponse(AjaxResponse $api_response, string $event_type = '') {
121  $api_response = $this->filterApiResponse($api_response, $event_type);
122  $response = $this->buildHttpResponse($api_response);
123 
124  $this->response_sent = true;
125  return _elgg_services()->responseFactory->send($response);
126  }
127 
136  public function respondWithError(string $msg = '', int $status = 400) {
137  $response = new JsonResponse(['error' => $msg], $status);
138 
139  // clear already set system messages as we respond directly with an error as message body
140  $this->msgs->dumpRegister();
141 
142  $this->response_sent = true;
143  return _elgg_services()->responseFactory->send($response);
144  }
145 
155  private function filterApiResponse(AjaxResponse $api_response, string $event_type = ''): AjaxResponse {
156  $api_response->setTtl($this->request->getParam('elgg_response_ttl', 0, false));
157 
158  if ($event_type) {
159  $event_name = AjaxResponse::RESPONSE_EVENT;
160  $api_response = $this->events->triggerResults($event_name, $event_type, [], $api_response);
161  if (!$api_response instanceof AjaxResponse) {
162  throw new RuntimeException("The value returned by event [{$event_name}, {$event_type}] was not an ApiResponse");
163  }
164  }
165 
166  return $api_response;
167  }
168 
177  private function buildHttpResponse(AjaxResponse $api_response): JsonResponse {
178  if ($api_response->isCancelled()) {
179  return new JsonResponse(['error' => 'The response was cancelled'], 400);
180  }
181 
182  $response = _elgg_services()->responseFactory->prepareJsonResponse($api_response->getData());
183 
184  $ttl = $api_response->getTtl();
185  if ($ttl > 0) {
186  // JsonRequest sets a default Cache-Control header we don't want
187  $response->headers->remove('Cache-Control');
188 
189  $response->setClientTtl($ttl);
190 
191  // if we don't set Expires, Apache will add a far-off max-age and Expires for us.
192  $response->headers->set('Expires', gmdate('D, d M Y H:i:s \G\M\T', time() + $ttl));
193  }
194 
195  return $response;
196  }
197 
206  public function prepareResponse(\Elgg\Event $event) {
207  $response = $event->getValue();
208  if (!$response instanceof AjaxResponse) {
209  return;
210  }
211 
212  if ($this->request->getParam('elgg_fetch_messages', true)) {
213  $messages = $this->msgs->dumpRegister();
214  foreach ($messages as $type => $msgs) {
215  $messages[$type] = array_map(function($value) {
216  return (string) $value;
217  }, $msgs);
218  }
219 
220  $response->getData()->_elgg_msgs = (object) $messages;
221  }
222 
223  if ($this->request->getParam('elgg_fetch_deps', true)) {
224  $response->getData()->_elgg_deps = $this->esm->getImports();
225  }
226 
227  return $response;
228  }
229 
237  public function registerView(string $view): void {
238  $this->allowed_views[$view] = true;
239  }
240 
248  public function unregisterView(string $view): void {
249  unset($this->allowed_views[$view]);
250  }
251 
257  public function getViews(): array {
258  return array_keys($this->allowed_views);
259  }
260 }
$messages
Definition: admin.php:12
isCancelled()
Has the response been cancelled?
respondFromOutput($output, string $event_type= '', bool $try_decode=true)
Send a JSON HTTP response with the given output.
Definition: Service.php:91
Elgg HTTP request.
Definition: Request.php:17
Exception thrown if an error which can only be found on runtime occurs.
Keeps track of ES modules.
Definition: ESMService.php:14
$response
Definition: content.php:10
setTtl($ttl=0)
Set the max-age for client caching.
isAjax2Request()
Did the request come from the elgg/Ajax module?
Definition: Service.php:48
$request
Definition: livesearch.php:12
$version
c Accompany it with the information you received as to the offer to distribute corresponding source complete source code means all the source code for all modules it plus any associated interface definition plus the scripts used to control compilation and installation of the executable as a special the source code distributed need not include anything that is normally and so on of the operating system on which the executable unless that component itself accompanies the executable If distribution of executable or object code is made by offering access to copy from a designated then offering equivalent access to copy the source code from the same place counts as distribution of the source even though third parties are not compelled to copy the source along with the object code You may not or distribute the Program except as expressly provided under this License Any attempt otherwise to sublicense or distribute the Program is void
Definition: LICENSE.txt:215
registerView(string $view)
Register a view to be available for ajax calls.
Definition: Service.php:237
Events service.
$type
Definition: delete.php:21
respondWithError(string $msg= '', int $status=400)
Send a JSON HTTP 400 response.
Definition: Service.php:136
Models the Ajax API service.
Definition: Service.php:19
if($item instanceof\ElggEntity) elseif($item instanceof\ElggRiverItem) elseif($item instanceof\ElggRelationship) elseif(is_callable([$item, 'getType']))
Definition: item.php:48
$value
Definition: generic.php:51
prepareResponse(\Elgg\Event $event)
Prepare the response with additional metadata, like system messages and required ES modules...
Definition: Service.php:206
if(!empty($avatar)&&!$avatar->isValid()) elseif(empty($avatar)) if(!$owner->saveIconFromUploadedFile('avatar')) if(!elgg_trigger_event('profileiconupdate', $owner->type, $owner)) $view
Definition: upload.php:39
bool $response_sent
Definition: Service.php:21
__construct(protected EventsService $events, protected SystemMessagesService $msgs, protected Request $request, protected ESMService $esm)
Constructor.
Definition: Service.php:33
decodeJson($string)
Attempt to JSON decode the given string.
Definition: Service.php:73
JSON endpoint response.
unregisterView(string $view)
Unregister a view for ajax calls.
Definition: Service.php:248
respondFromApiResponse(AjaxResponse $api_response, string $event_type= '')
Send a JSON HTTP response based on the given API response.
Definition: Service.php:120
if($email instanceof\Elgg\Email) $object
Definition: body.php:24
getData()
Get the response data, which will be a stdClass object with property "value".
System messages service.
array $allowed_views
Definition: Service.php:23
isReady()
Is the service ready to respond to the request?
Definition: Service.php:62
_elgg_services()
Get the global service provider.
Definition: elgglib.php:351
JSON endpoint response.
Definition: Response.php:13
$output
Definition: download.php:9
getTtl()
Get the max-age for client caching.
getViews()
Returns an array of views allowed for ajax calls.
Definition: Service.php:257
Models an event passed to event handlers.
Definition: Event.php:11