Typo3 Extbase AJAX without page typenum

2020-02-08 21:37发布

问题:

Is there any way to create AJAX calls in Extbase extension without using of page typeNum?

回答1:

Edit:

Helmut Hummel, a member of the TYPO3 CMS team, measured that using EID with Extbase is slower than using the typeNum approach. But since the typeNum approach is cumbersome to configure, there is a third way developed by him.

The extension typoscript_rendering provides a way to call Extbase actions directly without additional configuration. It contains a ViewHelper that generates such links and can be used like this in a Fluid template:

{namespace h=Helhum\TyposcriptRendering\ViewHelpers}
<script>
var getParticipationsUri = '<h:uri.ajaxAction controller="Participation" action="listByCompetition" arguments="{competition:competition}" />';
</script>

This generates an URI that calls the action "listByCompetition" of my "ParticipationController". You can pass arguments normally.

The only downside is that for security reasons, the extension uses the cHash to validate the request arguments. The cHash is submitted by GET but you cannot pass additional arguments by GET at the same time because it would invalidate the cHash. So if you want to pass form data in such a request, you need to mix GET (for a valid AJAX call) and POST (for submitting user data):

<script>
var createAddressUri = '<h:uri.ajaxAction controller="Address" action="create" />';
$body.on('submit', '#myForm', function(e) {
    e.preventDefault();
    emailAddress = $('#myForm').find('#email');
    if (typeof(emailAddress) === 'string') {
        $.ajax({
            url: createAddressUri,
            type: 'POST',
            data: { 'tx_myext_pluginname[address][email]' : emailAddress},
            success: function() {
              // things to do on success
            }
        })
    }
});
</script>

(Of course this is only a very basic example. You might post whole models etc.)

The EID way:

Yes, you can use the EID (Extension ID) mechanism for that. There is no official statement which way (pageType or eID) should be used for Extbase AJAX calls and it seems to be just a matter of taste.

There is a nice tutorial that can be found here and I copy the source code in here:

<?php

/** *************************************************************
 *
 * Extbase Dispatcher for Ajax Calls TYPO3 6.1 namespaces
 *
 * IMPORTANT Use this script only in Extensions with namespaces
 *
 * Klaus Heuer <klaus.heuer@t3-developer.com>
 *
 * This script is part of the TYPO3 project. The TYPO3 project is
 * free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * The GNU General Public License can be found at
 * http://www.gnu.org/copyleft/gpl.html.
 *
 * This script is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * This copyright notice MUST APPEAR in all copies of the script!
 * ************************************************************* */

/** ************************************************************
 * Usage of this script:
 *
 * - Copy this script in your Extension Dir in the Folder Classes
 * - Set the Vendor and Extension Name in Line 82 + 83
 * - Include the next line in the ext_localconf.php, change the ext name!
 * - $TYPO3_CONF_VARS['FE']['eID_include']['ajaxDispatcher'] = \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath('myExtension').'Classes/EidDispatcher.php';
 *
 * Use for Ajax Calls in your jQuery Code:
 *
 *     $('.jqAjax').click(function(e)  {
 *       var uid = $(this).find('.uid').html();
 *       var storagePid = '11';
 *      
 *       $.ajax({
 *           async: 'true',
 *           url: 'index.php',      
 *           type: 'POST', 
 *        
 *           data: {
 *               eID: "ajaxDispatcher",  
 *               request: {
 *                   pluginName:  'patsystem',
 *                   controller:  'Todo',
 *                   action:      'findTodoByAjax',
 *                   arguments: {
 *                       'uid': uid,
 *                       'storagePid': storagePid
 *                   }
 *               }
 *           },
 *           dataType: "json",      
 *          
 *           success: function(result) {
 *               console.log(result);
 *           },
 *           error: function(error) {
 *              console.log(error);               
 *           }
 *       });
 *************************************************************** */


/**
 * Gets the Ajax Call Parameters
 */
$ajax = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('request');

/**
 * Set Vendor and Extension Name
 *
 * Vendor Name like your Vendor Name in namespaces
 * ExtensionName in upperCamelCase
 */
$ajax['vendor'] = 'T3Developer';
$ajax['extensionName'] = 'ProjectsAndTasks';

/**
 * @var $TSFE \TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController
 */
$TSFE = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController', $TYPO3_CONF_VARS, 0, 0);
\TYPO3\CMS\Frontend\Utility\EidUtility::initLanguage();

// Get FE User Information
$TSFE->initFEuser();
// Important: no Cache for Ajax stuff
$TSFE->set_no_cache();

//$TSFE->checkAlternativCoreMethods();
$TSFE->checkAlternativeIdMethods();
$TSFE->determineId();
$TSFE->initTemplate();
$TSFE->getConfigArray();
\TYPO3\CMS\Core\Core\Bootstrap::getInstance()->loadConfigurationAndInitialize();

$TSFE->cObj = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer');
$TSFE->settingLanguage();
$TSFE->settingLocale();

/**
 * Initialize Database
 */
\TYPO3\CMS\Frontend\Utility\EidUtility::connectDB();

/**
 * @var $objectManager \TYPO3\CMS\Extbase\Object\ObjectManager
 */
$objectManager = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\CMS\Extbase\Object\ObjectManager');


/**
 * Initialize Extbase bootstap
 */
$bootstrapConf['extensionName'] = $ajax['extensionName'];
$bootstrapConf['pluginName'] = $ajax['pluginName'];

$bootstrap = new TYPO3\CMS\Extbase\Core\Bootstrap();
$bootstrap->initialize($bootstrapConf);

$bootstrap->cObj = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('tslib_cObj');

/**
 * Build the request
 */
$request = $objectManager->get('TYPO3\CMS\Extbase\Mvc\Request');

$request->setControllerVendorName($ajax['vendor']);
$request->setcontrollerExtensionName($ajax['extensionName']);
$request->setPluginName($ajax['pluginName']);
$request->setControllerName($ajax['controller']);
$request->setControllerActionName($ajax['action']);
$request->setArguments($ajax['arguments']);

$response = $objectManager->create('TYPO3\CMS\Extbase\Mvc\ResponseInterface');

$dispatcher = $objectManager->get('TYPO3\CMS\Extbase\Mvc\Dispatcher');

$dispatcher->dispatch($request, $response);

echo $response->getContent();
//die();
?>

Have a look at the "usage of this script" section that explains how to register the eID. The script works with TYPO3 6.1 and higher.



回答2:

For TYPO3 6.2 change the following line:

\TYPO3\CMS\Core\Core\Bootstrap::getInstance()->loadConfigurationAndInitialize();

to

\TYPO3\CMS\Core\Core\Bootstrap::getInstance()


回答3:

For Test Extension.

Include EID in the ext_localconf.php file

## Ajax configuration
$TYPO3_CONF_VARS['FE']['eID_include']['Test'] = \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath('test').'Classes/Ajax/EidDispatcher.php';

Create directory in classes – Classes/Ajax/EidDispatcher.php

namespace TYPO3\Test\Ajax;

class EidDispatcher {
    /**
   * @var \array
   */
    protected $configuration;

    /**
   * @var \array
   */
    protected $bootstrap;

    /**
   * The main Method
   *
   * @return \string
   */
    public function run() {
        return $this->bootstrap->run( '', $this->configuration );
    }

    /**
   * Initialize Extbase
   *
   * @param \array $TYPO3_CONF_VARS
   */
    public function __construct($TYPO3_CONF_VARS) {

        $ajaxRequest = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('tx_Test_addhours');

        // create bootstrap
        $this->bootstrap = new \TYPO3\CMS\Extbase\Core\Bootstrap();

        // get User
        $feUserObj = \TYPO3\CMS\Frontend\Utility\EidUtility::initFeUser();

        // set PID
        $pid = (\TYPO3\CMS\Core\Utility\GeneralUtility::_GET( 'id' )) ? \TYPO3\CMS\Core\Utility\GeneralUtility::_GET('id') : 1;

        // Create and init Frontend
        $GLOBALS['TSFE'] = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance( 'TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController', $TYPO3_CONF_VARS, $pid, 0, TRUE );
        $GLOBALS['TSFE']->connectToDB();
        $GLOBALS['TSFE']->fe_user = $feUserObj;
        $GLOBALS['TSFE']->id = $pid;
        $GLOBALS['TSFE']->determineId();
        $GLOBALS['TSFE']->getCompressedTCarray(); //Comment this line when used for TYPO3 7.6.0 on wards
        $GLOBALS['TSFE']->initTemplate();
        $GLOBALS['TSFE']->getConfigArray();
        $GLOBALS['TSFE']->includeTCA(); //Comment this line when used for TYPO3 7.6.0 on wards

        // Get Plugins TypoScript
        $TypoScriptService = new \TYPO3\CMS\Extbase\Service\TypoScriptService();
        $pluginConfiguration = $TypoScriptService->convertTypoScriptArrayToPlainArray($GLOBALS['TSFE']->tmpl->setup['plugin.']['tx_Test.']);

        // Set configuration to call the plugin
        $this->configuration = array (
                'pluginName' => $ajaxRequest['pluginName'],
                'vendorName' => 'TYPO3',
                'extensionName' => 'Test',
                'controller' => $ajaxRequest['controller'],
                'action' => $ajaxRequest['action'],
                'mvc' => array (
                        'requestHandlers' => array (
                                'TYPO3\CMS\Extbase\Mvc\Web\FrontendRequestHandler' => 'TYPO3\CMS\Extbase\Mvc\Web\FrontendRequestHandler'
                        )
                ),
                'settings' => $pluginConfiguration['settings'],
                'persistence' => array (
                        'storagePid' => $pluginConfiguration['persistence']['storagePid']
                )
        );

    }
}
global $TYPO3_CONF_VARS;
// make instance of bootstrap and run
$eid = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance( 'TYPO3\Test\Ajax\EidDispatcher', $TYPO3_CONF_VARS );
echo $eid->run();

Call From Script

$.ajax({
    async: 'true',
    url: 'index.php',      
    type: 'GET', 
    data: {
        eID: "Test",  
        tx_ExtName_PluginName: {
            pluginName:  'Plugin_Name',
            controller:  'Controller_Name',
            action:      'Action_Name',
        }
    },
    success:function(data){
        // code
    }
});


回答4:

I had to change the first 0 of the makeInstance to the id of the page for it to work.

$id = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('id');
$TSFE = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController', $TYPO3_CONF_VARS, $id, 0);


回答5:

I used a quick and probably dirty way without typeNum. I used jQuery ajax call the common way. My target action ended with the following.

$headers = DivUtilities::createHeader();
foreach ($headers as $header => $data) {
    $this->response->setHeader($header, $data);
}
$this->response->sendHeaders();
echo $this->view->render();
exit;

The createHeader Method

/**
  *
  * @param string $type
  * @return array
  */
public static function createHeader($type = 'html')
{
  switch ($type) {
    case 'txt':
            $cType   = 'text/plain';
            break;
    case 'html':
            $cType   = 'text/html';
            break;
    case 'json':
            $cType   = 'application/json';
            break;
    case 'pdf':
            $cType   = 'application/pdf';
            break;
  }
  $headers = array(
          'Pragma' => 'public',
          'Expires' => 0,
          'Cache-Control' => 'must-revalidate, post-check=0, pre-check=0',
          'Cache-Control' => 'public',
          'Content-Type' => $cType
  );
  return $headers;
}

The output is the template of the called action. This can be html, json or whatever u need.



标签: typo3 extbase