Verwendung und Verarbeitung von Fluid Markern im RTE

Bei der täglichen Arbeit mit Extbase und Fluid kommt auch das Bedürfnis auf, Fluid Marker in einem RTE Feld zu verarbeiten. Ob bei einem gewöhnlichen Content Element Text oder bei der Verwendung von RTE Feldern im eigenen Plugin Datensatz. 
Das nachfolgende Beispiel bezieht sich auf den Einsatz eines Content Elements "Text". 

Der erste Schritt ist die Definition einer speziellen View Klasse, da die Standard View zur Verarbeitung von Fluid Markern eine Template Datei voraussetzt. Zu diesem Zweck wird von der Standard View Klasse abgeleitet und eine Funktion für das Vorhaben definiert. 

  
class Tx_Placeholder_View_TemplateView extends Tx_Fluid_View_TemplateView {

    /**
     * Render template source ( without template file )
     *
     * @param string $source template source
     * @return string rendered content
     */
    public function renderSource($source) {
        $this->baseRenderingContext->setControllerContext($this->controllerContext);
        $this->templateParser->setConfiguration($this->buildParserConfiguration());
        $parsedTemplate = $this->templateParser->parse($source);

        if ($this->isLayoutDefinedInTemplate($parsedTemplate)) {
            $this->startRendering(self::RENDERING_LAYOUT, $parsedTemplate, $this->baseRenderingContext);
            $parsedLayout = $this->templateParser->parse($this->getLayoutSource($this->getLayoutNameInTemplate($parsedTemplate)));
            $output = $parsedLayout->render($this->baseRenderingContext);
            $this->stopRendering();
        } else {
            $this->startRendering(self::RENDERING_TEMPLATE, $parsedTemplate, $this->baseRenderingContext);
            $output = $parsedTemplate->render($this->baseRenderingContext);
            $this->stopRendering();
        }

        return $output;
    }

}

Diese View Klasse leitet von Tx_Fluid_View_TemplateView ab und muss anschließend im Controller definiert werden.

  
/**
  *
  * @var string
  * @override
  */
protected $defaultViewObjectName = 'Tx_Placeholder_View_TemplateView';

Im nächsten Schritt wird ein ViewHelper benötigt der in der Lage ist Content Elemente zu verarbeiten.  Der ViewHelper kann auch zur gewöhnlichen Verarbeitung von Content Elementen verwendet werden, dazu ist mindestens die UID des Datensatzes als Parameter nötigt. Im vorliegenden Beispiel soll aber die erweiterte Funktionalität, Auflösung von Fluid Markern aus dem RTE, demonstriert werden. Nachfolgend die ContentElementViewHelper Klasse gefolgt von der Zuweisung an die View im Controller und anschließend die Fluid Implementation. objectList muss vom Typ Array sein und kann, z.B. jedes Model der Extension enthalten. Alle Felder des, bzw. der Models stehen dann als Fluid Marker im RTE zur Verfügung, da alle Objekteigenschaften in der Content Element ViewHelper Klasse automatisch aufgelöst und zur Verfügung gestellt werden.

  
/**
 * Content Element Processing
 * 
 * @author Claus Fassing claus@fassing.eu
 */
class Tx_Placeholder_ViewHelpers_ContentElementViewHelper extends Tx_Fluid_Core_ViewHelper_AbstractViewHelper {

    /**
     * @var Tx_Extbase_Configuration_ConfigurationManagerInterface
     */
    protected $configurationManager;

    /**
     * @var Content Object
     */
    protected $cObj;
    
    /**
     * Injects the Configuration Manager
     *
     * @param Tx_Extbase_Configuration_ConfigurationManagerInterface $configurationManager
     * @return void
     */
    public function injectConfigurationManager(Tx_Extbase_Configuration_ConfigurationManagerInterface $configurationManager) {
        $this->configurationManager = $configurationManager;
        $this->cObj = $this->configurationManager->getContentObject();
    }    

    /**
     * Render the content
     *
     * @param int UID of any content element
     * @param array[object]. If available, build a marker array from object properties.
     * @param Tx_Placeholder_View_TemplateView the view object
     * @return string Parsed Content Element
     */
    public function render($uid, $objectList = NULL, $view = NULL) {
        $conf = array(
            'tables' => 'tt_content',
            'source' => $uid,
            'dontCheckPid' => 1
        );
        $content = $this->cObj->RECORDS($conf);
        if (!is_null($objectList) && !is_null($view)) {
            $marker = $this->buildMarkerArray($objectList);
            $this->view = $view;
            if (!is_null($result = $this->resolveRTEFluidMarker($content, $marker))) {
                return $result;
            }
        }
        return $content;
    }


    /**
     * Resolve the fluid marker from rte field
     *  
     * @param string $source
     * @param array $marker
     * @return string or null
     */
    private function resolveRTEFluidMarker($source, $marker) {
        if (empty($marker) || !is_array($marker))
            return NULL;

        $this->view->assignMultiple($marker);
        $content = $this->view->renderSource($source);

        return html_entity_decode($content, ENT_COMPAT, 'UTF-8');
    }

    /**
     * Build the marker array from objects
     * 
     * @param array $objectList
     * @return array the marker array
     */
    private function buildMarkerArray(array $objectList) {
        $markerArray = array();
        foreach ($objectList as $objectName => $object) {     
            $properties = Tx_Extbase_Reflection_ObjectAccess::getGettableProperties($object);
            foreach ($properties as $propertyName => $propertyValue) {
                $markerArray[$objectName . '_' . $propertyName] = $propertyValue;
            }
        }
        return $markerArray;
    }

}

      /**
     * Success action
     */
    public function successAction(){
        // Get object from session
        $foo = $this->sessionHandler->restoreFromSession($this->request->getControllerExtensionKey(), 'foo');
        // Get another object
        $bar = $this->barRepository->findOneByCode($foo->getTheValueFromProperty());
        // Get one more object
        if(!empty($bar)){
            $category = $this->categoryRepository->findOneByPurpose($bar);
        }

        $objectList = array('foo' => $foo, 'bar' => $bar, 'kategorie' => $category);
        $this->view->assignMultiple(array('objectList' => $objectList, 'contentID' => (integer) $this->settings['successContent'], 'view' => $this->view));
     
    }

  
{namespace custom=Tx_Placeholder_ViewHelpers}




    

Im RTE des Content Elements können nun Fluid Marker eingesetzt werden. Gemäß dem Beispiel könnte das wie folgt aussehen.
Sehr geehrte(r) {foo_anrede} {foo_vorname} {foo_nachname} vielen Dank für {kategorie_name} {bar_zweck} etc.
foo, bar und kategorie entsprechen dem string der Zuweisung in dem Array $objectList in der Controller Action, s.o.
Gefolgt von dem Trenner _ wird die Objekteigenschaft wie im Model definiert angegeben.
Das Content Element wurde in diesem Beispiel über eine Flexform Option am Plugin verfügbar gemacht und in $this->settings['successContent'] angesprochen, bzw. abgerufen.

Die Verarbeitung von Fluid Markern im RTE kann u.a. in der eigenen Extension interessant sein um dynamisch generierten und redaktionellen Inhalt zu migrieren, aber auch die Verwendung in zusätzlich integrierten Inhaltselementen, die per Flexform Option oder TypoScript definiert werden, um dynamischen und redaktionellen Inhalt zu migrieren kann als Zweck dienen.