Typo3 Extbase AJAX without page typenum - typo3

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

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.

For TYPO3 6.2 change the following line:
\TYPO3\CMS\Core\Core\Bootstrap::getInstance()->loadConfigurationAndInitialize();
to
\TYPO3\CMS\Core\Core\Bootstrap::getInstance()

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
}
});

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);

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.

Related

TYPO3 Extension - Redirect to another page in show action if no record is set or not available

How can I redirect to another page when someone access the detail page but without a record or if record is not available?
I have detail records like
domain.com/abc/ABC1234
When somone enters
domain.com/abc/
... I get:
Uncaught TYPO3 Exception
#1298012500: Required argument "record" is not set for Vendor\Extension\Controller\ActionController->show. (More information)
TYPO3\CMS\Extbase\Mvc\Controller\Exception\RequiredArgumentMissingException thrown in file
/is/htdocs/www/typo3_src-8.7.11/typo3/sysext/extbase/Classes/Mvc/Controller/AbstractController.php in line 425.
... in this case I want it to redirect to:
domain.com/other-page/
... I also need it if a specific record is not available.
... how to do so?
/**
* action show
*
* #param \Action $record
* #return void
*/
public function showAction(Action $record) {
$this->view->assign('record', $record);
}
Here are some examples TYPO3 Extbase - redirect to pid ... but not sure how to implement it
Edit: What works is ...
/**
* action show
*
* #param \Action $record
* #return void
*/
public function showAction(Action $record=null) {
if ($record === null) {
$pageUid = 75;
$uriBuilder = $this->uriBuilder;
$uri = $uriBuilder
->setTargetPageUid($pageUid)
->build();
$this->redirectToUri($uri, 0, 404);
} else {
$this->view->assign('record', $record);
}
}
The redirect method needs an action and controller parameter. So your redirect code is wrong.
$this->redirect($actionName, $controllerName = NULL, $extensionName = NULL, array $arguments = NULL, $pageUid = NULL, $delay = 0, $statusCode = 303);
To redirect to an PageUID you need to use the uriBuilder and the redirectToUri method. See here for an example.
This should do the trick:
public function showAction(Action $record=null) {
if ($record === null) {
$this->redirect(/* add parameters as needed */);
} else {
// other code
}
Alternative Solution (from Simon Oberländer)
public function intializeShowAction() {
if (!$this->request->hasArgument('record')) {
$this->redirect(/* add parameters as needed */); // stops further execution
}
}
Your question suggests that there should be an other action without arguments, probably a listAction, that is the DEFAULT action. The default action gets called when no action is specified. It is the first action enlisted in the ExtensionUtility::configurePlugin() call.
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin(
'Vendor.' . $_EXTKEY,
'Pluginname',
array(
'Domainobject' => 'list, show',
),
// non-cacheable actions
array(
'Domainobject' => 'list, show',
)
);
Regarding > The identity property "TTTT" is no UID
You have to distinguish between no parameter and an invalid parameter. For the latter you can add #ignorevalidation to the showAction comments and do your validation testing within the action - or you can leave it to extbase that displays the error message you have seen.
Where would you get a link like domain.com/abc/TTTT/ from anyhow? Unless the link is expired.
BTW: in a production system you would disable the display of exceptions, thus the display of the website would work.
This could be a solution:
```
/**
* Show a booking object
*
* #return void
* #throws \TYPO3\CMS\Extbase\Mvc\Exception\NoSuchArgumentException
*/
public function showAction()
{
$bookingObject = null;
$bookingObjectUid = 0;
if ($this->request->hasArgument('bookingObject')) {
$bookingObjectUid = (int)$this->request->getArgument('bookingObject');
}
if ($bookingObjectUid > 0) {
$bookingObject = $this->bookingObjectRepository->findByIdentifier($bookingObjectUid);
}
if (!($bookingObject instanceof BookingObject)) {
$messageBody = 'Booking object can\'t be displayed.';
$messageTitle = 'Error';
$this->addFlashMessage($messageBody, $messageTitle, AbstractMessage::ERROR);
$this->redirect('list');
}
$this->view->assign('bookingObject', $bookingObject);
}
```

How can I add an action to a TYPO3 frontend plugin?

I am using powermail and extending it with powermail_extended and want to add a new action to what the frontend plugin is doing.
Extending the Controller is not the issue: It is overloaded via XCLASS:
config.tx_extbase.objects {
In2code\Powermail\Controller\FormController.className = In2code\PowermailExtended\Controller\FormController
}
But simply calling this action is not enough, because the prefences are stored in the frontend plugin in the backend. This frontend plugin is configured in ext_localconf.php of powermail. How can a add a new action to this frontend plugin?
(Using TYPO3 7 LTS)
After reading the code of \TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin it is actually easier than I thought:
Add the following code to ext_localconf.php of powermailextended:
if (!function_exists('configure_plugin_add_action')) {
/**
* Add a action to a existing frontend plugin
*
* #param string $extensionName The extension name (in UpperCamelCase) or the extension key (in lower_underscore)
* #param string $pluginName must be a unique id for your plugin in UpperCamelCase (the string length of the extension key added to the length of the plugin name should be less than 32!)
* #param string $controllerName Name of the Controller
* #param string $newAction Name of the action
* #param bool $cachable Can this action be cached?
*
* #see \TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin
*/
function configure_plugin_add_action($extensionName, $pluginName, $controllerName, $newAction, $cachable = true) {
$delimiterPosition = strrpos($extensionName, '.');
if ($delimiterPosition !== false) {
$extensionName = substr($extensionName, $delimiterPosition + 1);
}
$extensionName = str_replace(' ', '', ucwords(str_replace('_', ' ', $extensionName)));
$newAction = trim($newAction);
$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extbase']['extensions'][$extensionName]['plugins'][$pluginName]['controllers'][$controllerName]['actions'][] = $newAction;
if (!$cachable) {
$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extbase']['extensions'][$extensionName]['plugins'][$pluginName]['controllers'][$controllerName]['nonCacheableActions'][] = $newAction;
}
}
}
You can use it like this (also in ext_localconf.php):
configure_plugin_add_action('In2code.powermail', 'Pi1', 'Form', 'debug', false);
This should work in Typo3 7-9 (as the configurePlugin-Function didn't really change).

TYPO3: Uploads in backend module

I have to implement a "Book" management in the Backend. Each book has a PDF preview, a title, description and so on...
The BE user should be able to upload a PDF and set a title, description etc. through a Backend module.
The created Book should be selectable in a plugin (or content element ?) so it can be display in the frontend.
Also, the uploaded PDF should only be downloadable by a certain group of FE users.
I don't know how to handle the upload part in the backend. I didn't find much info online beside this upload example: https://github.com/helhum/upload_example it seems quite complex and I'm not sure if it's the best solution for me.
What would be the best way to proceed for my task ?
Use File Abstraction Layer (FAL). You don't need the example in backend, but it's great for frontend upload.
Domain/Model/Book.php
...
/**
* File (file references)
*
* #var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\TYPO3\CMS\Extbase\Domain\Model\FileReference>
* #lazy
*/
protected $files = NULL;
/**
* Construct
*
*
*/
public function __construct() {
//Do not remove the next line: It would break the functionality
$this->initStorageObjects();
}
/**
* Initializes all ObjectStorage properties
* Do not modify this method!
* It will be rewritten on each save in the extension builder
* You may modify the constructor of this class instead
*
* #return void
*/
protected function initStorageObjects() {
$this->files = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();
}
/**
* Set files (file references)
*
* #param \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\TYPO3\CMS\Extbase\Domain\Model\FileReference> $files
* #return void
*/
public function setFiles(\TYPO3\CMS\Extbase\Persistence\ObjectStorage $files) {
$this->files = $files;
}
/**
* Get files (file references)
*
* #return \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\TYPO3\CMS\Extbase\Domain\Model\FileReference> $files
*/
public function getFiles() {
return $this->files;
}
...
TCA/tx_yourextension_domain_model_book.php
...
'files' => [
'label' => 'LLL:EXT:werkhandkunst/Resources/Private/Language/locallang_db.xlf:file',
'config' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::getFileFieldTCAConfig(
'files', ['
maxitems' => 25,
],
$GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext']
),
],
...
ext_tables.sql
CREATE TABLE tx_yourextension_domain_model_book (
...
files int(11) unsigned DEFAULT '0' NOT NULL,
...
)

PEAR QuickForm2 CSRF Protection

I was looking for a way to ensure CSRF-Protection in my Quickform2.
I found this link but it's for QuickForm1.
Any ideas how I can adapt this to QF2?
After some fiddling around I came up with this solution.
Maybe it helps someone else as well:
<?php
/**
* #uses HTML_QuickForm
* #desc Add automatic CSRF mitigation to all forms by incorporating a token that must be matched in the session and forcing the use of POST method
* Based on: http://www.zapoyok.info/2010/07/17/csrf-et-quickform-de-pear/
*/
require_once "QuickForm2.php";
class HTML_QuickForm2s extends HTML_QuickForm2
{
/**
* #property string $_sessionTokenKey The name of the session variable containing the token
*/
private $_sessionTokenKey;
/**
* #method __construct
* #desc Override the method to always use post and pass it on to the parent constructor. Create a session key for the token based on the form name.
* #param $id
* #param string $method
* #param mixed $attributes
* #param boolean $trackSubmit
*/
public function __construct($id, $method = 'post', $attributes = null, $trackSubmit = true)
{
$this->_sessionTokenKey = "QuickForm2s_" . md5($id);
parent::__construct($id, $method, $attributes, $trackSubmit);
//A token hasn't been created so do so
if (!isset($_SESSION[$this->_sessionTokenKey])) {
$_SESSION[$this->_sessionTokenKey] = md5(uniqid(rand(), true) . session_id()); //requires the session id to be known in order to add extra difficulty to compromising
}
//Hide the token at the end of the form
$this->addElement("hidden", "qfS_csrf");
$qfsCsrf= $this->getElementsByName('qfS_csrf');
$qfsCsrf[0]->setValue($_SESSION[$this->_sessionTokenKey]);
}
/**
* #method validate
* #desc Check if the passed token matches the session before allowing validation
* #return boolean
*/
public function validate()
{
$submitValues = $this->getValue();
//The token was not passed or does not match
if (!isset($submitValues['qfS_csrf']) || $submitValues['qfS_csrf'] != $_SESSION[$this->_sessionTokenKey]) {
$this->setError("Anti-CSRF token does not match");
}
return parent::validate();
}
}

Persisting language fields

In my extbase model, I created getters and setters for the fields t3_origuid, sys_language_uid, and l10n_parent.
When setting these fields and persisting, only the l10n_parent field is updated in the database. Is it possible to change the other fields, without manually querying the database of course.
To set sys_language_uid through extbase you need to use the internal API AbstractDomainObject::_setProperty() with $entity->_setProperty('_languageUid', $languageUid) where $languageUid would be the id of your langage record. You will find a more complete example on forge: https://forge.typo3.org/issues/61722.
You could also use this small service I've written to translate any domain object easily:
<?php
/*
* 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!
*/
use TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface;
use TYPO3\CMS\Extbase\Persistence\Generic\Mapper\ColumnMap;
use TYPO3\CMS\Core\SingletonInterface;
use TYPO3\CMS\Core\Utility\GeneralUtility;
/**
* Provides services to translate domain objects
*/
class TranslationService implements SingletonInterface {
/**
* #var \TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapper
* #inject
*/
protected $dataMapper;
/**
* Translates a domain object
*
* #param DomainObjectInterface $origin
* #param DomainObjectInterface $translation
* #param int $language
* #throws \Exception
* #return void
*/
public function translate(DomainObjectInterface $origin, DomainObjectInterface $translation, $language) {
if (get_class($origin) !== get_class($translation)) {
throw new \Exception('Origin and translation must be the same type.', 1432499926);
}
$dataMap = $this->dataMapper->getDataMap(get_class($origin));
if (!$dataMap->getTranslationOriginColumnName()) {
throw new \Exception('The type is not translatable.', 1432500079);
}
if ($origin === $translation) {
throw new \Exception('Origin can\'t be translation of its own.', 1432502696);
}
$propertyName = GeneralUtility::underscoredToLowerCamelCase($dataMap->getTranslationOriginColumnName());
if ($translation->_setProperty($propertyName, $origin) === FALSE) {
$columnMap = $dataMap->getColumnMap($propertyName);
$columnMap->setTypeOfRelation(ColumnMap::RELATION_HAS_ONE);
$columnMap->setType($dataMap->getClassName());
$columnMap->setChildTableName($dataMap->getTableName());
$translation->{$propertyName} = $origin;
}
$translation->_setProperty('_languageUid', $language);
}
}
You have define your fields in the TCA.
'sys_language_uid' => array(
'config' => array(
'type' => 'passthrough'
)
)
And the same for the other fields...
there are some tutorials in the web for mapping tables of typo3 with extbase.
this tutorial is in german, but the code speaks for itself.