Hey,
I’m using your suggestion allready for parts of my navigation structure - but it doen’t seem to be quite useable for “normal” links. So i took the link.action and ifHasRole viewhelpers and made a frankenstein-hybrid-like viewhelper

I ended up with this:
<?php
namespace MY\Package\ViewHelpers\Link;
/*
* Copyright here
*/
use TYPO3\Fluid\Core\ViewHelper\AbstractTagBasedViewHelper;
use TYPO3\Fluid\Core\ViewHelper;
use TYPO3\Flow\Annotations as Flow;
use TYPO3\Flow\Security\Account;
use TYPO3\Flow\Security\Context;
use TYPO3\Flow\Security\Policy\PolicyService;
use TYPO3\Flow\Security\Policy\Role;
use TYPO3\Fluid\Core\ViewHelper\AbstractConditionViewHelper;
/**
* A view helper for creating links to actions - if allowed to!
* = Example =
* <code title="With Security enabled">
* <my:link.action action="edit" arguments="{account: user}" role="MY.Package:Admin">Edit the User!</my:link.action>
* </code>
* <output>
* (If actual authenticated User has the Role MY.Package:Admin)
* <a href="/Package/Controller/edit?account%5B__identity%5D=0123456a-c1d2-1234-1234-1f234567890d">Edit the User!</a>
* (If not just plain text is shown)
* Edit the User!
* </output>
*
* @api
*/
class ActionViewHelper extends AbstractTagBasedViewHelper
{
/**
* @var string
*/
protected $tagName = 'a';
/**
* @Flow\Inject
* @var Context
*/
protected $securityContext;
/**
* @Flow\Inject
* @var PolicyService
*/
protected $policyService;
/**
* Initialize arguments
*
* @return void
* @api
*/
public function initializeArguments()
{
$this->registerUniversalTagAttributes();
$this->registerTagAttribute('name', 'string', 'Specifies the name of an anchor');
$this->registerTagAttribute('rel', 'string', 'Specifies the relationship between the current document and the linked document');
$this->registerTagAttribute('rev', 'string', 'Specifies the relationship between the linked document and the current document');
$this->registerTagAttribute('target', 'string', 'Specifies where to open the linked document');
}
/**
* Render the link.
*
* @param string $action Target action
* @param array $arguments Arguments
* @param string $controller Target controller. If NULL current controllerName is used
* @param string $package Target package. if NULL current package is used
* @param string $subpackage Target subpackage. if NULL current subpackage is used
* @param string $section The anchor to be added to the URI
* @param string $format The requested format, e.g. ".html"
* @param array $additionalParams additional query parameters that won't be prefixed like $arguments (overrule $arguments)
* @param boolean $addQueryString If set, the current query parameters will be kept in the URI
* @param array $argumentsToBeExcludedFromQueryString arguments to be removed from the URI. Only active if $addQueryString = TRUE
* @param boolean $useParentRequest If set, the parent Request will be used instead of the current one
* @param boolean $absolute By default this ViewHelper renders links with absolute URIs. If this is FALSE, a relative URI is created instead
*
* @param string $role The role or role identifier
* @param string $rolePackageKey PackageKey of the package defining the role
* @param Account $account If specified, this subject of this check is the given Account instead of the currently authenticated account
*
* @return string The rendered link
* @throws ViewHelper\Exception
* @api
*/
public function render($action, $arguments = array(), $controller = null, $package = null, $subpackage = null, $section = '', $format = '', array $additionalParams = array(), $addQueryString = false, array $argumentsToBeExcludedFromQueryString = array(), $useParentRequest = false, $absolute = true,
$role = null, $rolePackageKey = null, Account $account = null )
{
if (is_string($role)) {
$roleIdentifier = $role;
if (in_array($roleIdentifier, array('Everybody', 'Anonymous', 'AuthenticatedUser'))) {
$roleIdentifier = 'TYPO3.Flow:' . $roleIdentifier;
}
if (strpos($roleIdentifier, '.') === false && strpos($roleIdentifier, ':') === false) {
if ($rolePackageKey === null) {
$request = $this->controllerContext->getRequest();
$roleIdentifier = $request->getControllerPackageKey() . ':' . $roleIdentifier;
} else {
$roleIdentifier = $rolePackageKey . ':' . $roleIdentifier;
}
}
$role = $this->policyService->getRole($roleIdentifier);
}
if ($account instanceof Account) {
$hasRole = $account->hasRole($role);
} else {
$hasRole = $this->securityContext->hasRole($role->getIdentifier());
}
if (($hasRole)||((!$hasRole)&&(null === $role))) {
/** generate the link as originally done in link viewhelper start **/
$uriBuilder = $this->controllerContext->getUriBuilder();
if ($useParentRequest) {
$request = $this->controllerContext->getRequest();
if ($request->isMainRequest()) {
throw new ViewHelper\Exception('You can\'t use the parent Request, you are already in the MainRequest.', 1360163536);
}
$uriBuilder = clone $uriBuilder;
$uriBuilder->setRequest($request->getParentRequest());
}
$uriBuilder
->reset()
->setSection($section)
->setCreateAbsoluteUri($absolute)
->setArguments($additionalParams)
->setAddQueryString($addQueryString)
->setArgumentsToBeExcludedFromQueryString($argumentsToBeExcludedFromQueryString)
->setFormat($format);
try {
$uri = $uriBuilder->uriFor($action, $arguments, $controller, $package, $subpackage);
} catch (\Exception $exception) {
throw new ViewHelper\Exception($exception->getMessage(), $exception->getCode(), $exception);
}
$this->tag->addAttribute('href', $uri);
$this->tag->setContent($this->renderChildren());
$this->tag->forceClosingTag(true);
return $this->tag->render();
/** generate the link as originally done in link viewhelper stop **/
} else {
/** generate only the link text start **/
return $this->renderChildren();
/** generate only the link text stop **/
}
}
}
Perhaps someone else can use it, too… 