Create an eID script for ajax requests

Object oriented, Request and Response Object, ...

Works with TYPO3 7 LTS, 8 LTS, 9 LTS

Create a class for your eID controller

First we need a class that we can use as an eID controller. It could be useful to create an AbstractEidController class adapted to your needs, if you wan´t to add more than one eID controller. In my case I´ll stay with one controller so I don´t create one.

Put the controller (and abstract controller if you created one) into Classes/Controller folder of your extension. Now you have at least one empty class inside your extension.

 

<?php
declare(strict_types=1);
namespace Crynton\Tutorial\Controller;

/*
 * This file is part of the TYPO3 CMS project.
 *
 * It is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License, either version 2
 * of the License, or any later version.
 *
 * For the full copyright and license information, please read the
 * LICENSE.txt file that was distributed with this source code.
 *
 * The TYPO3 project - inspiring people to share!
 */

/**
 * Class CommentController
 */
class CommentController
{
}

 

 

Add an entry point method

Before we going to register the eID class it´s required to add an entry point for the eID class. This method will be fired when we call the eID url. Inside of it we need to process the incoming request and we should return a response object.

Since TYPO3 7.6 the PSR-7 ServerRequest and Response objects are passed to the entry point method of our eID script. We´ll add both of them as parameter.

I´ll name the method processRequest but this is not defined in the coding guidelines so you can decide how you wan´t to name it.

 

<?php
...

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;

...

/**
 * @param ServerRequestInterface $request
 * @param ResponseInterface $response
 * @return ResponseInterface
 */
public function processRequest(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
}

 

 

Register the eID class

Now we are ready to at least register the class to show TYPO3 what we´ve made.

Add or edit the file ext_localconf.php inside your extension. There we need to add an array entry using the identifier as key and the class name and method as value (PSR-2). 

 

<?php
$GLOBALS['TYPO3_CONF_VARS']['FE']['eID_include']['tx_tutorial_comment'] =
    \Crynton\Tutorail\Controller\CommentController::class . '::processRequest';

 

In my case the identifier is tx_tutorial_comment. You can call the script using /index.php?eID=<identifier> later. In my case it would be /index.php?eID=tx_tutorial_comment.

But let´s finish the eID class first.

Process your request

We added the entry point method of the eID script earlier. Now we put some code into it.

In this example we want to process the request after an action that has been passed to the url /index.php?eID=tx_tutorial_comment&action=add.
We could use the GeneralUtility to read the $_GET or $_POST array but you can also use $request->getQueryParams() from ServerRequestInterface instead.

Maybe you´ll use a simple if for your processRequest or just doing some stuff in that single method but if you wan´t to have some "actions" then you can do it like me adding a switch case. I love them :)

 

<?php

/**
 * @param ServerRequestInterface $request
 * @param ResponseInterface $response
 * @return ResponseInterface
 */
public function processRequest(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
    $this->initializeLanguage();
    $this->initializeData($request);

    switch (isset($request->getQueryParams()['action']) ? (string)$request->getQueryParams()['action'] : '') {
        case 'add':
            $this->addAction();
            break;
        case 'check':
            $this->checkAction();
            break;
        case 'remove':
            $this->removeAction();
            break;
        default:
            throw new \UnexpectedValueException('No or unknown action passed!', 1543418482439);
    }

    $this->prepareResponse($response);
    return $response;
}

 

 

Initialize LanguageService in eID class

I made a little tutorial in a seperate article how multilanguage can be used inside an eID script.

Go to the tutorial

I´ll just use the default language in my initializeLanguage() method to keep it simple.

 

<?php
...

use TYPO3\CMS\Core\Localization\LanguageService;

...

/**
 * @return void
 */
protected function initializeLanguage()
{
    if (!isset($GLOBALS['LANG']) || !\is_object($GLOBALS['LANG'])) {
        $GLOBALS['LANG'] = GeneralUtility::makeInstance(LanguageService::class);
        $GLOBALS['LANG']->init('default');
    }
}

 

 

Initialize input data using ServerRequestInterface

I don´t like putting everything into one method. Because of this I also put the initialization of user data into an extra method. In this method I´ll validate (required) parameters.

 

<?php
...

/**
 * @var string 
 */
protected $name = '';

/**
 * @var string 
 */
protected $mail = '';

/**
 * @var string 
 */
protected $message = '';

...

/**
 * @param ServerRequestInterface $request
 * @return void
 */
protected function initializeData(ServerRequestInterface $request)
{
    if (
        !isset($request->getQueryParams()['name'])
        || !$name = (string)$request->getQueryParams()['name']
    ) {
        throw new \InvalidArgumentException('No message passed!', 1543419903286);
    }
    if (
        !isset($request->getQueryParams()['mail'])
        || !$mail = (string)$request->getQueryParams()['mail']
    ) {
        throw new \InvalidArgumentException('No mail passed!', 1543419903286);
    }
    if (
        !isset($request->getQueryParams()['message'])
        || !$message = (string)$request->getQueryParams()['message']
    ) {
        throw new \InvalidArgumentException('No message passed!', 1543419903286);
    }
    $this->name = $name;
    $this->mail = $mail;
    $this->message = $message;
}

 

 

Use ResponseInterface to return JSON

Because we are using this eID class for AJAX requests, we should return a JSON response. I´ll use the ResponseInterface and a separate method to do this. My return value will be set in some of my actions. I don´t want to add a return value for my actions so I use a property $responseArray to store that what later will be returned as JSON object. In my actions I´ll modify that property.

Later in a prepeareReponse() method I´ll add the content type and encode + write the $responseArray.

 

<?php
...

/**
 * @var array
 */
protected $responseArray = [
    'hasErrors' => false,
    'message' => ''
];

...

/**
 * Add a new comment
 *
 * @return void
 */
protected function addAction()
{
    if (!$this->commentRepository->insertRecord($this->name, $this->mail, $this->message)) {
        $this->responseArray['hasErrors'] = true;
        $this->responseArray['message'] = $this->translate('message.could_not_add_comment');
    }
}

/**
 * @param string $key
 * @return string
 */
protected function translate(string $key): string
{
    return $GLOBALS['LANG']->sL('LLL:EXT:tutorial/Resources/Private/Language/locallang.xlf:' . $key);
}

/**
 * @param ResponseInterface $response
 * @return void
 */
protected function prepareResponse(ResponseInterface &$response)
{
    $response = $response->withHeader('Content-Type', 'application/json; charset=utf-8');
    $response->getBody()->write(\json_encode($this->responseArray));
}

...