typo3 and extbase: generate a frontendlink in a backend hook

Some basics first: my extension is called ophi_inserat and allows users to create ads in the frontend. The model is called “Ad” and is saved in tx_ophiinserat_domain_model_ad in my database. Those ads can be edited in the backend and as soon as hidden is set to 0 an email is supposed to be sent to the creator of the ad with a link to edit the created ad.

Step 1: creating a hook to do something after saving a model

I added the following line to the ext_localconf.php of my extension:

$GLOBALS ['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processDatamapClass'][] = 'EXT:'.$_EXTKEY.'/Classes/Hook/NotificationHook.php:Ophi\OphiInserat\Hook\NotificationHook';

Now I created ophi_inserat/Classes/Hook/NotificationHook.php with the function processDatamap_postProcessFieldArray. Since I only needed this to happen when editing my ad table, I added an if right at the beginnning to check for the right table:

namespace Ophi\OphiInserat\Hook;
class NotificationHook {
    public function processDatamap_postProcessFieldArray($status, $table, $id, &$fieldArray, &$reference){
        if ($table == 'tx_ophiinserat_domain_model_ad') {
			//insert code here
		}
	}
}

The hidden value is available in $fieldArray, so I can use that. Since this is all happening in the backend context, it gets more difficult from here on out. First of all, I made sure I had the ad accessible:

if ($table == 'tx_ophiinserat_domain_model_ad') {
	if($fieldArray['hidden'] == 0){
		//fetch some classes
		$objectManager = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('\TYPO3\CMS\Extbase\Object\ObjectManager');
		$persistenceManager = $objectManager->get('\TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager');
		$adRepository = $objectManager->get('\Ophi\OphiInserat\Domain\Repository\AdRepository');

		//fetch the ad in question
		$ad = $adRepository->findOneByUid($id);
	}
}

Since the page in question is available in 2 languages, this is where the problems start. The e-mail is supposed to be in the right language, according to whatever language the user was using when entering the ad. So the correct language uid should be stored in the sys_language_uid field.

Step 2: Translating texts

I asked stackoverflow and there actually is a way to access the parsed translation file. This requires the LanguageFactory and using the languageKey (“en”, “de”, etc.) and the path to the translation file results in an array with all the default values in “default” and the translated values in “en” or “de” or whichever languagekey was used. I wrote myself a little function to return the correct value from the languageKey or, if not yet set, the default value:

private function getTranslation($data, $languageKey, $target){
	if(isset($data[$languageKey][$target])){
		return $data[$languageKey][$target][0]['target'];
	}  else {
		return $data['default'][$target][0]['target'];
	}
}

And the part in my processDatamap_postProcessFieldArray function:

$languageFactory = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('\TYPO3\CMS\Core\Localization\LocalizationFactory');
$langId = $ad->getSysLanguageUid();
$languageKey = $langId == 1 ? 'en' : 'de';
$data = $languageFactory->getParsedData('EXT:ophi_inserat/Resources/Private/Language/locallang.xlf', $languageKey);
$text1 = $this->getTranslation($data, $languageKey, 'tx_ophiinserat_domain_model_ad.email.text1');

Step 3: generating the link

It seems impossible to get a hold of the uribuilder in the typo3 backend context. So what I did was the following: create a plugin which outputs the link using uribuilder and in my backend hook all I do is fetch the content of the page using file_get_contents. So let’s start with creating the plugin:

\TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin(
	'Ophi.' . $_EXTKEY,
	'AdFormLink',
	array(
		'Ad' => 'generateLink',
	),
	// non-cacheable actions
	array(
		'Ad' => 'generateLink',
	)
);

The setup.txt:

ajax_frontend_url < page
ajax_frontend_url {
    typeNum = 1447752540
    config {
        disableAllHeaderCode = 1
        xhtml_cleaning = 0
        admPanel = 0
    }
    10 = USER
    10 {
        extensionName = OphiInserat
        pluginName = AdFormLink
        vendorName = Ophi
        userFunc = tx_extbase_core_bootstrap->run
    }
}

Now the URL /index.php?type=1447752540&id=123 is available, wherein 123 is any random typo3 page. In the AdController I do the following:

public function generateLinkAction(){
	$link = $this->uriBuilder
		->setCreateAbsoluteUri(true)
		->setTargetPageUid(123)
		->setArguments( array('tx_ophiinserat_adform' => array('code' => '12354567') ) )
		->build();
	die($link);
}

now all I that is left is the backend call to read this page’s content. So I did this using the following functions:

/**
 * I have no idea why $pageId is necessary
 *
 * @param $pageId
 * @return string
 */
private function getSiteUrl($pageId){
	$objectManager = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('\TYPO3\CMS\Extbase\Object\ObjectManager');
	$beFunc = $objectManager->get('\TYPO3\CMS\Backend\Utility\BackendUtility');
	$libDiv = $objectManager->get('\TYPO3\CMS\Core\Utility\GeneralUtility');
	$utilityHttp = $objectManager->get('\TYPO3\CMS\Core\Utility\HttpUtility');
	$domain = $beFunc::firstDomainRecord($beFunc::BEgetRootLine(60));
	$pageRecord = $beFunc::getRecord('pages', 60);
	$scheme = is_array($pageRecord) && isset($pageRecord['url_scheme']) && $pageRecord['url_scheme'] == $utilityHttp::SCHEME_HTTPS ? 'https' : 'http';
	$siteUrl = $domain ? $scheme . '://' . $domain . '/' : $libDiv::getIndpEnv('TYPO3_SITE_URL');
	return $siteUrl;
}

/**
 * generate the link to the adForm in a convoluted, weird way because there seems to be no other option
 * @param $code
 * @return string
 */
private function generateLink($code){
	$objectManager = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('\TYPO3\CMS\Extbase\Object\ObjectManager');
	$libDiv = $objectManager->get('\TYPO3\CMS\Core\Utility\GeneralUtility');

	//fetch the base url first
	$siteUrl = $this->getSiteUrl($this->ajaxPageId);
	//now set the ajax url
	$url = $siteUrl.'index.php?type=1447752540&id='.$this->ajaxPageId;
	//set headers because otherwise it doesn't work
	$headers = array(
		'Cookie: fe_typo_user=' . $_COOKIE['fe_typo_user']
	);
	//as far as I understand it, this is the equivalent of file_get_contents
	$result = $libDiv::getURL($url, false, $headers);

	//with luck $result should contain a valid link now.
	return $result;
}

And now generateLink returns the necessary link. Whew. The completed NotificationHook.php can be downloaded here: NotificationHook

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.