Quantcast
Channel: Insane in the Main Frame
Viewing all articles
Browse latest Browse all 310

typo3 and extbase: generate a frontendlink in a backend hook

$
0
0

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:

  1. $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:

  1. <?php
  2. namespace Ophi\OphiInserat\Hook;
  3. class NotificationHook {
  4. public function processDatamap_postProcessFieldArray($status, $table, $id, &$fieldArray, &$reference){
  5. if ($table == 'tx_ophiinserat_domain_model_ad') {
  6. //insert code here
  7. }
  8. }
  9. }

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:

  1. if ($table == 'tx_ophiinserat_domain_model_ad') {
  2. if($fieldArray['hidden'] == 0){
  3. //fetch some classes
  4. $objectManager = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('\TYPO3\CMS\Extbase\Object\ObjectManager');
  5. $persistenceManager = $objectManager->get('\TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager');
  6. $adRepository = $objectManager->get('\Ophi\OphiInserat\Domain\Repository\AdRepository');
  7. //fetch the ad in question
  8. $ad = $adRepository->findOneByUid($id);
  9. }
  10. }

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:

  1. private function getTranslation($data, $languageKey, $target){
  2. if(isset($data[$languageKey][$target])){
  3. return $data[$languageKey][$target][0]['target'];
  4. } else {
  5. return $data['default'][$target][0]['target'];
  6. }
  7. }

And the part in my processDatamap_postProcessFieldArray function:

  1. $languageFactory = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('\TYPO3\CMS\Core\Localization\LocalizationFactory');
  2. $langId = $ad->getSysLanguageUid();
  3. $languageKey = $langId == 1 ? 'en' : 'de';
  4. $data = $languageFactory->getParsedData('EXT:ophi_inserat/Resources/Private/Language/locallang.xlf', $languageKey);
  5. $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:

  1. \TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin(
  2. 'Ophi.' . $_EXTKEY,
  3. 'AdFormLink',
  4. array(
  5. 'Ad' => 'generateLink',
  6. ),
  7. // non-cacheable actions
  8. array(
  9. 'Ad' => 'generateLink',
  10. )
  11. );

The setup.txt:

  1. ajax_frontend_url < page
  2. ajax_frontend_url {
  3. typeNum = 1447752540
  4. config {
  5. disableAllHeaderCode = 1
  6. xhtml_cleaning = 0
  7. admPanel = 0
  8. }
  9. 10 = USER
  10. 10 {
  11. extensionName = OphiInserat
  12. pluginName = AdFormLink
  13. vendorName = Ophi
  14. userFunc = tx_extbase_core_bootstrap->run
  15. }
  16. }

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:

  1. public function generateLinkAction(){
  2. $link = $this->uriBuilder
  3. ->setCreateAbsoluteUri(true)
  4. ->setTargetPageUid(123)
  5. ->setArguments( array('tx_ophiinserat_adform' => array('code' => '12354567') ) )
  6. ->build();
  7. die($link);
  8. }

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

  1. /**
  2. * I have no idea why $pageId is necessary
  3. *
  4. * @param $pageId
  5. * @return string
  6. */
  7. private function getSiteUrl($pageId){
  8. $objectManager = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('\TYPO3\CMS\Extbase\Object\ObjectManager');
  9. $beFunc = $objectManager->get('\TYPO3\CMS\Backend\Utility\BackendUtility');
  10. $libDiv = $objectManager->get('\TYPO3\CMS\Core\Utility\GeneralUtility');
  11. $utilityHttp = $objectManager->get('\TYPO3\CMS\Core\Utility\HttpUtility');
  12. $domain = $beFunc::firstDomainRecord($beFunc::BEgetRootLine(60));
  13. $pageRecord = $beFunc::getRecord('pages', 60);
  14. $scheme = is_array($pageRecord) && isset($pageRecord['url_scheme']) && $pageRecord['url_scheme'] == $utilityHttp::SCHEME_HTTPS ? 'https' : 'http';
  15. $siteUrl = $domain ? $scheme . '://' . $domain . '/' : $libDiv::getIndpEnv('TYPO3_SITE_URL');
  16. return $siteUrl;
  17. }
  18. /**
  19. * generate the link to the adForm in a convoluted, weird way because there seems to be no other option
  20. * @param $code
  21. * @return string
  22. */
  23. private function generateLink($code){
  24. $objectManager = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('\TYPO3\CMS\Extbase\Object\ObjectManager');
  25. $libDiv = $objectManager->get('\TYPO3\CMS\Core\Utility\GeneralUtility');
  26. //fetch the base url first
  27. $siteUrl = $this->getSiteUrl($this->ajaxPageId);
  28. //now set the ajax url
  29. $url = $siteUrl.'index.php?type=1447752540&id='.$this->ajaxPageId;
  30. //set headers because otherwise it doesn't work
  31. $headers = array(
  32. 'Cookie: fe_typo_user=' . $_COOKIE['fe_typo_user']
  33. );
  34. //as far as I understand it, this is the equivalent of file_get_contents
  35. $result = $libDiv::getURL($url, false, $headers);
  36. //with luck $result should contain a valid link now.
  37. return $result;
  38. }

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


Viewing all articles
Browse latest Browse all 310

Trending Articles