Elgg  Version master
Service.php
Go to the documentation of this file.
1 <?php
2 
3 namespace Elgg\Ajax;
4 
11 use Symfony\Component\HttpFoundation\JsonResponse;
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 }
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
$type
Definition: delete.php:21
return[ 'admin/delete_admin_notices'=>['access'=> 'admin'], 'admin/menu/save'=>['access'=> 'admin'], 'admin/plugins/activate'=>['access'=> 'admin'], 'admin/plugins/activate_all'=>['access'=> 'admin'], 'admin/plugins/deactivate'=>['access'=> 'admin'], 'admin/plugins/deactivate_all'=>['access'=> 'admin'], 'admin/plugins/set_priority'=>['access'=> 'admin'], 'admin/security/security_txt'=>['access'=> 'admin'], 'admin/security/settings'=>['access'=> 'admin'], 'admin/security/regenerate_site_secret'=>['access'=> 'admin'], 'admin/site/cache/invalidate'=>['access'=> 'admin'], 'admin/site/flush_cache'=>['access'=> 'admin'], 'admin/site/icons'=>['access'=> 'admin'], 'admin/site/set_maintenance_mode'=>['access'=> 'admin'], 'admin/site/set_robots'=>['access'=> 'admin'], 'admin/site/theme'=>['access'=> 'admin'], 'admin/site/unlock_upgrade'=>['access'=> 'admin'], 'admin/site/settings'=>['access'=> 'admin'], 'admin/upgrade'=>['access'=> 'admin'], 'admin/upgrade/reset'=>['access'=> 'admin'], 'admin/user/ban'=>['access'=> 'admin'], 'admin/user/bulk/ban'=>['access'=> 'admin'], 'admin/user/bulk/delete'=>['access'=> 'admin'], 'admin/user/bulk/unban'=>['access'=> 'admin'], 'admin/user/bulk/validate'=>['access'=> 'admin'], 'admin/user/change_email'=>['access'=> 'admin'], 'admin/user/delete'=>['access'=> 'admin'], 'admin/user/login_as'=>['access'=> 'admin'], 'admin/user/logout_as'=>[], 'admin/user/makeadmin'=>['access'=> 'admin'], 'admin/user/resetpassword'=>['access'=> 'admin'], 'admin/user/removeadmin'=>['access'=> 'admin'], 'admin/user/unban'=>['access'=> 'admin'], 'admin/user/validate'=>['access'=> 'admin'], 'annotation/delete'=>[], 'avatar/upload'=>[], 'comment/save'=>[], 'diagnostics/download'=>['access'=> 'admin'], 'entity/chooserestoredestination'=>[], 'entity/delete'=>[], 'entity/mute'=>[], 'entity/restore'=>[], 'entity/subscribe'=>[], 'entity/trash'=>[], 'entity/unmute'=>[], 'entity/unsubscribe'=>[], 'login'=>['access'=> 'logged_out'], 'logout'=>[], 'notifications/mute'=>['access'=> 'public'], 'plugins/settings/remove'=>['access'=> 'admin'], 'plugins/settings/save'=>['access'=> 'admin'], 'plugins/usersettings/save'=>[], 'register'=>['access'=> 'logged_out', 'middleware'=>[\Elgg\Router\Middleware\RegistrationAllowedGatekeeper::class,],], 'river/delete'=>[], 'settings/notifications'=>[], 'settings/notifications/subscriptions'=>[], 'user/changepassword'=>['access'=> 'public'], 'user/requestnewpassword'=>['access'=> 'public'], 'useradd'=>['access'=> 'admin'], 'usersettings/save'=>[], 'widgets/add'=>[], 'widgets/delete'=>[], 'widgets/move'=>[], 'widgets/save'=>[],]
Definition: actions.php:73
JSON endpoint response.
Definition: Response.php:13
Models the Ajax API service.
Definition: Service.php:19
respondFromOutput($output, string $event_type='', bool $try_decode=true)
Send a JSON HTTP response with the given output.
Definition: Service.php:91
respondFromApiResponse(AjaxResponse $api_response, string $event_type='')
Send a JSON HTTP response based on the given API response.
Definition: Service.php:120
isAjax2Request()
Did the request come from the elgg/Ajax module?
Definition: Service.php:48
array $allowed_views
Definition: Service.php:23
bool $response_sent
Definition: Service.php:21
registerView(string $view)
Register a view to be available for ajax calls.
Definition: Service.php:237
prepareResponse(\Elgg\Event $event)
Prepare the response with additional metadata, like system messages and required ES modules.
Definition: Service.php:206
isReady()
Is the service ready to respond to the request?
Definition: Service.php:62
respondWithError(string $msg='', int $status=400)
Send a JSON HTTP 400 response.
Definition: Service.php:136
getViews()
Returns an array of views allowed for ajax calls.
Definition: Service.php:257
decodeJson($string)
Attempt to JSON decode the given string.
Definition: Service.php:73
unregisterView(string $view)
Unregister a view for ajax calls.
Definition: Service.php:248
__construct(protected EventsService $events, protected SystemMessagesService $msgs, protected Request $request, protected ESMService $esm)
Constructor.
Definition: Service.php:33
Models an event passed to event handlers.
Definition: Event.php:11
Events service.
Exception thrown if an error which can only be found on runtime occurs.
Elgg HTTP request.
Definition: Request.php:17
Keeps track of ES modules.
Definition: ESMService.php:14
System messages service.
$version
if($email instanceof \Elgg\Email) $object
Definition: body.php:24
if($item instanceof \ElggEntity) elseif($item instanceof \ElggRiverItem) elseif($item instanceof \ElggRelationship) elseif(is_callable([ $item, 'getType']))
Definition: item.php:48
$output
Definition: download.php:9
_elgg_services()
Get the global service provider.
Definition: elgglib.php:353
$value
Definition: generic.php:51
JSON endpoint response.
getTtl()
Get the max-age for client caching.
getData()
Get the response data, which will be a stdClass object with property "value".
$request
Definition: livesearch.php:12
if(parse_url(elgg_get_site_url(), PHP_URL_PATH) !=='/') if(file_exists(elgg_get_root_path() . 'robots.txt'))
Set robots.txt.
Definition: robots.php:10
$messages
Definition: admin.php:12
$response
Definition: content.php:10