-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fluid compilation is disabled for templates with (pagination) widgets #28
Comments
Comment created by @bwaidelich: A quick update: It won't be easy to solve this for all widgets.. But in general we (Sebastian & me) think that widgets might be deprecated at some point because (apart from this issue) there are several problems with them (e.g. tight coupling to MVC layers of Flow, expensive in terms of memory & performance, ...). <f:paginate objects="{invoices}" as="paginatedInvoices" partial="My.Package:Pagination">
<-- ... -->
</f:paginate> the partial argument would fallback to sth like "TYPO3.Fluid:Pagination" |
Comment created by @bwaidelich: FYI I got this to work in a custom project: <?php
namespace Acme\SomePackage\ViewHelpers;
use TYPO3\Flow\Annotations as Flow;
use TYPO3\Flow\Mvc\ActionRequest;
use TYPO3\Flow\Persistence\QueryResultInterface;
use TYPO3\Fluid\Core\ViewHelper\AbstractViewHelper;
use TYPO3\Fluid\Core\ViewHelper\Exception as ViewHelperException;
/****
* A pagination ViewHelper that works similar to Fluids paginate widget, but as standard ViewHelper without sub request!
*/
class PaginateViewHelper extends AbstractViewHelper {
/****
* @var boolean
*/
protected $escapeOutput = FALSE;
/****
* @param QueryResultInterface|\Iterator|array $objects
* @param string $as
* @param integer $itemsPerPage
* @param string $ifEmpty
* @param string $argumentName
* @param integer $maximumNumberOfLinks
* @param boolean $insertAbove
* @param boolean $insertBelow
* @return string
* @throws ViewHelperException
*/
public function render($objects, $as, $itemsPerPage = 30, $ifEmpty = NULL, $argumentName = 'page', $maximumNumberOfLinks = 10, $insertAbove = FALSE, $insertBelow = TRUE) {
if (!$objects instanceof QueryResultInterface && !$objects instanceof \Iterator && !is_array($objects)) {
throw new ViewHelperException(sprintf('The paginate ViewHelper only supports objects of QueryResultInterface, Iterator or array, given: "%s"', get_class($objects)), 1426778650);
}
$numberOfObjects = count($objects);
if ($numberOfObjects === 0 && $ifEmpty !== NULL) {
return $ifEmpty;
}
$numberOfPages = (integer)ceil($numberOfObjects / $itemsPerPage);
/*** @var ActionRequest $actionRequest **/
$actionRequest = $this->controllerContext->getRequest();
$currentPageNumber = (integer)$actionRequest->getInternalArgument('**' . $argumentName);
if ($currentPageNumber < 1) {
$currentPageNumber = 1;
} elseif ($currentPageNumber > $numberOfPages) {
$currentPageNumber = $numberOfPages;
}
$content = '';
$pagination = $this->buildPagination($currentPageNumber, $numberOfPages, $maximumNumberOfLinks);
$paginationLinks = $this->renderPaginationLinks($pagination, $actionRequest->getControllerActionName(), $argumentName);
if ($insertAbove) {
$content .= $paginationLinks;
}
$this->templateVariableContainer->add($as, $this->limitObjects($objects, $itemsPerPage, max(0, $itemsPerPage * ($currentPageNumber - 1))));
$content .= $this->renderChildren();
$this->templateVariableContainer->remove($as);
if ($insertBelow) {
$content .= $paginationLinks;
}
return $content;
}
/****
* @param QueryResultInterface|\Iterator|array $objects
* @param integer $limit
* @param integer $offset
* @return QueryResultInterface|\Iterator|array same type as $objects parameter
*/
protected function limitObjects($objects, $limit, $offset) {
if ($objects instanceof QueryResultInterface) {
$query = $objects->getQuery();
$query->setLimit($limit);
if ($offset > 0) {
$query->setOffset($offset);
}
return $query->execute();
}
if ($objects instanceof \Iterator) {
return new \LimitIterator($objects, $offset, $limit);
}
if (is_array($objects)) {
return array_slice($objects, $offset, $limit);
}
}
/****
* @param integer $currentPageNumber
* @param integer $numberOfPages
* @param integer $maximumNumberOfLinks
* @return array in the format array('currentPageNumber' => 2, 'numberOfPages' => 123, 'previousPage' => array(), 'nextPage' => array(...), 'pages' => array(array('number' => 1, 'isCurrent' => TRUE), ...))
*/
protected function buildPagination($currentPageNumber, $numberOfPages, $maximumNumberOfLinks = NULL) {
if ($currentPageNumber < 1) {
$currentPageNumber = 1;
} elseif ($currentPageNumber > $numberOfPages) {
$currentPageNumber = $numberOfPages;
}
if ($maximumNumberOfLinks === NULL || $maximumNumberOfLinks > $numberOfPages) {
$maximumNumberOfLinks = $numberOfPages;
}
$pagination = array(
'currentPageNumber' => $currentPageNumber,
'numberOfPages' => $numberOfPages,
);
if ($currentPageNumber > 1) {
$pagination['previousPage'] = $this->createPageLink($currentPageNumber - 1, $currentPageNumber, 'previous');
} else {
$pagination['previousPage'] = NULL;
}
if ($currentPageNumber < $numberOfPages) {
$pagination['nextPage'] = $this->createPageLink($currentPageNumber <ins> 1, $currentPageNumber, 'next');
} else {
$pagination['nextPage'] = NULL;
}
$delta = floor($maximumNumberOfLinks / 2);
$displayRangeStart = $currentPageNumber - $delta;
$displayRangeEnd = $currentPageNumber </ins> $delta <ins> ($maximumNumberOfLinks % 2 === 0 ? 1 : 0);
if ($displayRangeStart < 1) {
$displayRangeEnd -= $displayRangeStart - 1;
}
if ($displayRangeEnd > $numberOfPages) {
$displayRangeStart -= ($displayRangeEnd - $numberOfPages);
}
$displayRangeStart = (integer)max($displayRangeStart, 1);
$displayRangeEnd = (integer)min($displayRangeEnd, $numberOfPages);
$pages = array();
if ($displayRangeStart > 1) {
$pages[] = $this->createPageLink(1);
if ($displayRangeStart > 2) {
$pages[] = $this->createPageLink(NULL);
}
}
if ($numberOfPages > 1) {
for ($pageNumber = $displayRangeStart; $pageNumber <= $displayRangeEnd; $pageNumber</ins><ins>) {
$pages[] = $this->createPageLink($pageNumber, $currentPageNumber);
}
}
if ($displayRangeEnd < $numberOfPages) {
if ($displayRangeEnd </ins> 1 < $numberOfPages) {
$pages[] = $this->createPageLink(NULL);
}
$pages[] = $this->createPageLink($numberOfPages);
}
$pagination['pages'] = $pages;
return $pagination;
}
/****
* @param array $pagination
* @param string $actionName
* @param string $pageArgumentName
* @return string
*/
public function renderPaginationLinks(array $pagination, $actionName, $pageArgumentName) {
$arguments = array(
'pagination' => $pagination,
'actionName' => $actionName,
'pageArgumentName' => $pageArgumentName,
);
if ($this->templateVariableContainer->exists('settings')) {
$arguments['settings'] = $this->templateVariableContainer->get('settings');
}
return $this->viewHelperVariableContainer->getView()->renderPartial('Pagination', NULL, $arguments);
}
/****
* @param integer $pageNumber NULL => '...'
* @param integer $currentPageNumber
* @param string $label
* @return array
*/
protected function createPageLink($pageNumber, $currentPageNumber = NULL, $label = NULL) {
$pageLink = array();
if ($pageNumber === NULL) {
$pageLink['isEllipsis'] = TRUE;
$pageLink['label'] = '...';
} else {
$pageLink['label'] = $pageNumber;
}
if ($label !== NULL) {
$pageLink['label'] = $label;
}
$pageLink['arguments'] = $pageNumber > 1 ? array('**' . $this->arguments['argumentName'] => $pageNumber) : NULL;
$pageLink['isCurrent'] = $currentPageNumber !== NULL && $pageNumber === $currentPageNumber;
$pageLink['isLinked'] = $pageNumber !== NULL && $pageNumber !== $currentPageNumber;
return $pageLink;
}
} Currently it's hard-coded to a partial <div class="pagination pagination-centered">
<ul>
<f:if condition="{pagination.previousPage}">
<li class="previous">
<f:link.action action="{actionName}" addQueryString="true" arguments="{pagination.previousPage.arguments}">«</f:link.action>
</li>
</f:if>
<f:for each="{pagination.pages}" as="page">
<f:if condition="{page.isLinked}">
<f:then>
<li>
<f:link.action action="{actionName}" addQueryString="true" arguments="{page.arguments}">{page.label}</f:link.action>
</li>
</f:then>
<f:else>
<li class="{f:if(condition: page.isCurrent, then: 'active', else: 'disabled')}">
<span>{page.label}</span>
</li>
</f:else>
</f:if>
</f:for>
<f:if condition="{pagination.nextPage}">
<li class="next">
<f:link.action action="{actionName}" addQueryString="true" arguments="{pagination.nextPage.arguments}">»</f:link.action>
</li>
</f:if>
</ul>
</div> |
Jira issue originally created by user @bwaidelich:
Since https://forge.typo3.org/issues/28544 Fluid compiles templates into PHP when they are parsed for the first time.
But this compilation is disabled if a ViewHelper is used, that:
ChildNodeAccessInterface
andCompilableInterface
This is true for all widgets by default.
This is especially bad in the case of the PaginateViewHelper that is commonly used in large templates that could benefit profoundly from being compiled.
Maybe we can fix this for all widgets, but at least we should try to implement the
CompilableInterface
in the PaginateViewHelper.I just stumbled upon this issue by chance - we should consider some kind of logging for non-compilable templates.
Jira-URL: https://jira.neos.io/browse/FLOW-196
The text was updated successfully, but these errors were encountered: