[TYPO3-mvc] render fluid partial in backend Scheduler task

typo3 at litedesigns.nl typo3 at litedesigns.nl
Thu Aug 30 15:56:30 CEST 2012


Hi Claus,

No problem, not sure if it will be usefull, but here goes. This will be
quite a long mail, therefore i have omitted the class comments. If you
decide to add these ViewHelpers to FED, please don't forget to credit
Sebastian and Dmitry.

These viewhelpers need Dmitry Dulepov's pagepath extension:
http://typo3.org/extensions/repository/view/pagepath, otherwise they won't
work!

Next you need the Tx_MyExt_ViewHelpers_Be_Link_PagePathViewHelper from
http://blog.schreibersebastian.de/2011/11/frontend-links-im-backend-generieren/
There are no changes needed to this PagePathViewHelper. But this
PagePathViewHelper is needed by the ObjectLinkViewHelper! (which i will
describe below)

Based on Sebastian Schreiber's idea, i've extended the
Tx_MyExt_Link_WhateverLinkViewHelper to be able to reuse the ViewHelper
for all Extbase objects (at least all Extbase objects i need :)

=======================================================================

The modified WhateverLinkViewHelper is now called ObjectLinkViewHelper:

<?php
class Tx_MyExt_ViewHelpers_Link_ObjectLinkViewHelper extends
Tx_Fluid_Core_ViewHelper_AbstractViewHelper
{
	/**
     *
     * @var Tx_MyExt_ViewHelpers_Be_Link_PagePathViewHelper
     */
    protected $pagePathViewHelper = NULL;

    /**
     *
     * @param Tx_MyExt_ViewHelpers_Be_Link_PagePathViewHelper
$pagePathViewHelper
     */
    public function
injectPagePathViewHelper(Tx_MyExt_ViewHelpers_Be_Link_PagePathViewHelper
$pagePathViewHelper) {
        $this->pagePathViewHelper = $pagePathViewHelper;
    }

	/**
	 * Initialize arguments
	 * @return void
	 */
	public function initializeArguments() {
		parent::initializeArguments();
		$this->registerArgument('namespace', 'string', 'Plugin namespace', TRUE);
		$this->registerArgument('action', 'string', 'Extbase action to call',
TRUE);
		$this->registerArgument('controller', 'string', 'Extbase controller to
call', TRUE);
		$this->registerArgument('argumentName', 'string', 'Extbase name of
object param', TRUE);
	}

    /**
     * @param integer $pid The pid for the single view
     * @param Mixed $object
     */
    public function render($pid, $object = NULL) {
    	if (NULL === $object)
        {
            $object = $this->renderChildren();
        }
		if ($object instanceof Tx_Extbase_Persistence_LazyLoadingProxy)
		{
			$object = $object->_loadRealInstance();
		}
        if ($object != NULL && $object->getUid())
        {
            $parameters = array();
            $parameters[$this->arguments['namespace']] = array();
            $parameters[$this->arguments['namespace']][$this->arguments['argumentName']]
= $object->getUid();
            $parameters[$this->arguments['namespace']]['controller'] =
$this->arguments['controller'];
            $parameters[$this->arguments['namespace']]['action'] =
$this->arguments['action'];
            return $this->pagePathViewHelper->render($pid, $parameters);
        }
    }
}
?>

And this new ViewHelper can be used both in the backend and in the
frontend. For instance in a Blog / Post situation and you want to link to
a single Post:

{namespace myhelpers=Tx_MyExt_ViewHelpers}
<myhelpers:link.objectLink controller="Post" action="show"
namespace="tx_myext_post" argumentName="post"
pid="{settings.singlePid}">{post}</myhelpers:link.objectLink>

This will result in a link like:
index.php?id=8&tx_myext_post[controller]=Post&tx_myext_post[action]=show&tx_myext_post[post]=17
If for instance realurl is installed and enabled, the link will be
rewritten according normal realurl logic setup for your params, you don't
need to do anything for that.

=======================================================================

I have extended your fed:image viewhelper to remove a trailing slash in
front of my image src params.

<?php
class Tx_MyExt_ViewHelpers_ImageViewHelper extends
Tx_Fed_ViewHelpers_ImageViewHelper {

	/**
	 * Initialize arguments
	 * @return void
	 */
	public function initializeArguments() {
		parent::initializeArguments();
		$this->registerArgument('forceFrontEndImageSrc', 'boolean', 'If TRUE,
does not place a / in front of the Image src url', FALSE, TRUE);

	}

	/**
	 * Returns the proper new src value for an img tag
	 *
	 * @param string $src
	 * @param array $setup
	 * @return string
	 */
	protected function renderImage($src, $setup)
	{
		list($imageSource, $imageSourceOver) = parent::renderImage($src, $setup);

		if (strpos($imageSource, '/') === 0 &&
$this->arguments['forceFrontEndImageSrc'])
		{
			// remove trailing slash from the image $src
			$imageSource = substr($imageSource, 1);
		}

		if (strpos($imageSourceOver, '/') === 0 &&
$this->arguments['forceFrontEndImageSrc'])
		{
			// remove trailing slash from the image $src
			$imageSourceOver = substr($imageSourceOver, 1);
		}

		return array($imageSource, $imageSourceOver);
	}
}
?>

The ViewHelper can be used in the same was as the fed:image viewhelper.

=======================================================================

The reason i posted my question to the mailing list was because i wanted
to be able to cache my partial templates from within the backend
Scheduler. I will not post my Scheduler code here, because that is a
little overkill for this already lengthy mail. Basically you can render
your partial template from within the backend scheduler if you use
Tx_Fed_Service_Render->renderTemplateFile() and your partial template
needs to use the ObjectLinkViewHelper instead of f:link. Next you can use
the caching framework to cache your partial within your scheduler task.

And as a bonus, my Partial viewhelper which extends
Tx_Fluid_ViewHelpers_RenderViewHelper. This partial viewhelper will cache
the partial if it is called for the first time (or the cache expired), or
it will return the cached partial (not tested for sections). Please note
that in my own code i've written a wrapper service class for the Typo3
Caching Framework, i've rewritten the class below a bit to omit this
service class (to avoid code not needed here) and directly use the caching
framework. I have not tested the code below (it is tested and working with
my custom wrapper service for all my partials though!).

<?php
class Tx_MyExt_ViewHelpers_RenderViewHelper extends
Tx_Fluid_ViewHelpers_RenderViewHelper {

	/**
	 * objectManager
	 *
	 * @var Tx_Extbase_Object_ObjectManagerInterface
	 */
	protected $objectManager;

	/**
 	 * @param Tx_Extbase_Object_ObjectManagerInterface $objectManager
	 */
	public function __construct(Tx_Extbase_Object_ObjectManagerInterface
$objectManager)
	{
		$this->objectManager = $objectManager;
	}

	/**
	 * Renders the content.
	 *
	 * @param string $section Name of section to render. If used in a layout,
renders a section of the main content file. If used inside a standard
template, renders a section of the same file.
	 * @param string $partial Reference to a partial.
	 * @param array $arguments Arguments to pass to the partial.
	 * @param boolean $optional Set to TRUE, to ignore unknown sections, so
the definition of a section inside a template can be optional for a
layout
	 * @return string
	 * @api
	 */
	public function render($section = NULL, $partial = NULL, $arguments =
array(), $optional = FALSE)
	{
		if (isset($arguments['identifier']))
		{
			// get instance of caching framework
			$cache = $GLOBALS['typo3CacheManager']->getCache('myext_mycache');

			$identifierPrefix = '';
			if (isset($arguments['identifierPrefix']))
			{
				// Identifier prefix can be used to cache the same partial template
multiple times. If for instance the same partial is rendered with
different sizes of thumbnails in different views / pages
				$identifierPrefix = $arguments['identifierPrefix'];
			}

			// create unique identifier for this cache entry
			$cacheIdentifier = sha1('myext_mycache_partial_' . $partial .
$identifierPrefix . $arguments['identifier']);

			if (!$partialOutput = $cache->get($cacheIdentifier))	// if the entry is
not yet cached
			{
				// let the parent render the output
				$partialOutput = parent::render($section, $partial, $arguments,
$optional);

				// save the output to the cache
				$cache->set($cacheIdentifier, $partialOutput, array(),
Tx_MyExt_Service_CacheService::CACHING_LIFETIME);
			}
		}
		else
		{
			// no identifier was found. Just let the parent render the partial and
nothing gets cached
			$partialOutput = parent::render($section, $partial, $arguments,
$optional);
		}

		// return the partial
		return $partialOutput;
	}
}
?>

To render a partial that will cache itself and return a cached version of
itself if it exists use this fluid code. In this example we are showing
list items of Blog posts. So u can use this partial in a foreach loop in
your list.

{namespace myhelpers=Tx_MyExt_ViewHelpers}
<myhelpers:render partial="Post/ListItem" arguments="{post: post,
identifier: post.uid}" />

Please note that identifier: post.uid is the reason the partial is cached.

Hope this helps anyone!

Kind regards,
Tim

ps. @Claus, should you decide to add some of this stuff to FED, i would
love to hear :)



> Hi Tim,
>
> On Aug 30, 2012, at 9:40 AM, typo3 at litedesigns.nl wrote:
>
>> I've chosen to write my own viewhelpers
>
> Good to hear you found a solution :)
>
> If you want to share those ViewHelpers I would be happy to include them in
> FED.
>
> Cheers,
> Claus
> _______________________________________________
> TYPO3-project-typo3v4mvc mailing list
> TYPO3-project-typo3v4mvc at lists.typo3.org
> http://lists.typo3.org/cgi-bin/mailman/listinfo/typo3-project-typo3v4mvc
>



More information about the TYPO3-project-typo3v4mvc mailing list