Attention
TYPO3 v10 has reached end-of-life as of April 30th 2023 and is no longer being maintained. Use the version switcher on the top left of this page to select documentation for a supported version of TYPO3.
Need more time before upgrading? You can purchase Extended Long Term Support (ELTS) for TYPO3 v10 here: TYPO3 ELTS.
Backend¶
An AJAX endpoint in the TYPO3 backend is usually implemented as a method in a regular controller. The method receives a
request object implementing the Psr\Http\Message\ServerRequestInterface
, which allows to access all aspects of
the requests and returns an appropriate response in a normalized way. This approach is standardized as PSR-7.
Create a Controller¶
By convention, a controller is placed within the extension's Controller
directory, optionally in a subdirectory.
To have such controller, create a new ExampleController
in Classes/Controller/ExampleController.php
inside your extension.
The controller doesn't need that much logic right now. We'll create a method
called doSomethingAction()
which will be our AJAX endpoint. And we
inject the ResponseFactoryInterface
later needed to create our response.
See Creating Response Objects in PSR 17.
<?php
declare(strict_types = 1);
namespace Vendor\MyExtension\Controller;
use Psr\Http\Message\ResponseFactoryInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
class ExampleController
{
/** @var ResponseFactoryInterface */
private $responseFactory;
public function __construct(ResponseFactoryInterface $responseFactory)
{
$this->responseFactory = $responseFactory;
}
public function doSomethingAction(ServerRequestInterface $request): ResponseInterface
{
// TODO: return ResponseInterface
}
}
In its current state, the method doesn't do anything yet. We can add a very generic handling that exponentiates an
incoming number by 2. The incoming value will be passed as a query string argument named input
.
public function doSomethingAction(ServerRequestInterface $request): ResponseInterface
{
$input = $request->getQueryParams()['input'] ?? null;
if ($input === null) {
throw new \InvalidArgumentException('Please provide a number', 1580585107);
}
$result = $input ** 2;
// TODO: return ResponseInterface
}
Note
This is a really simple example. Something like this should not be used in production, as such feature is available in JavaScript as well.
We have computed our result by using the exponentiation operator, but we don't do anything with it yet. It's time to
build a proper response. A response implements the Psr\Http\Message\ResponseInterface
and its constructor
accepts the following arguments:
- $body
| Condition: required | Type: string |
The content of the response.
- $statusCode
| Condition: optional | Type: int | Default: 200 |
The HTTP status code of the response. The default of
200
meansOK
.- $headers
| Condition: optional | Type: array | Default: '[]' |
Headers to be sent with the response.
- $reasonPhrase
| Condition: optional | Type: string | Default: '' |
A reason for the given status code. If omitted, the default for the used status code will be used.
public function doSomethingAction(ServerRequestInterface $request): ResponseInterface
{
// our previous computation
$data = ['result' => $result];
$response = $this->responseFactory->createResponse()
->withHeader('Content-Type', 'application/json; charset=utf-8');
$response->getBody()->write(json_encode($data));
return $response;
}
Register the Endpoint¶
The endpoint must be registered as route. Create a file called Configuration/Backend/AjaxRoutes.php
in your
extension. The file basically just returns an array of route definitions. Every route in this file will be exposed to
JavaScript automatically. Let's register our endpoint now:
<?php
return [
'example_dosomething' => [
'path' => '/example/do-something',
'target' => \Vendor\MyExtension\Controller\ExampleController::class . '::doSomethingAction',
],
];
The naming of the key example_dosomething
and path /example/do-something
are up to you, but should contain the
controller name and action name to avoid potential conflicts with other existing routes.
For further reading, take a look at Backend Routing.
Important
Flushing caches is mandatory after modifying any route definition.
Use in AJAX¶
Since the route is registered in AjaxRoutes.php
its exposed to JavaScript now and stored in the global
TYPO3.settings.ajaxUrls
object identified by the used key in the registration. In this example it's
TYPO3.settings.ajaxUrls.example_dosomething
.
You are now free to use the endpoint in any of your AJAX calls. To complete this example, we'll ask the server to compute our input and write the result into the console.
require(['TYPO3/CMS/Core/Ajax/AjaxRequest'], function (AjaxRequest) {
// Generate a random number between 1 and 32
const randomNumber = Math.ceil(Math.random() * 32);
new AjaxRequest(TYPO3.settings.ajaxUrls.example_dosomething)
.withQueryArguments({input: randomNumber})
.get()
.then(async function (response) {
const resolved = await response.resolve();
console.log(resolved.result);
});
});