Initial commit

This commit is contained in:
2018-04-02 08:07:38 +02:00
commit 7330c1ed3e
2054 changed files with 405203 additions and 0 deletions

View File

@@ -0,0 +1,79 @@
<?php
namespace FluidTYPO3\Vhs\ViewHelpers\Iterator;
/*
* This file is part of the FluidTYPO3/Vhs project under GPLv2 or later.
*
* For the full copyright and license information, please read the
* LICENSE.md file that was distributed with this source code.
*/
use TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper;
/**
* Abstract class with basic functionality for loop view helpers.
*
* @author Danilo Bürger <danilo.buerger@hmspl.de>, Heimspiel GmbH
* @package Vhs
* @subpackage ViewHelpers\Iterator
*/
abstract class AbstractLoopViewHelper extends AbstractViewHelper {
/**
* Initialize
*
* @return void
*/
public function initializeArguments() {
$this->registerArgument('iteration', 'string', 'Variable name to insert result into, suppresses output', FALSE, NULL);
}
/**
* @param integer $i
* @param integer $from
* @param integer $to
* @param integer $step
* @param string $iterationArgument
* @return string
*/
protected function renderIteration($i, $from, $to, $step, $iterationArgument) {
if (FALSE === empty($iterationArgument)) {
$cycle = intval(($i - $from) / $step) + 1;
$iteration = array(
'index' => $i,
'cycle' => $cycle,
'isOdd' => (0 === $cycle % 2 ? FALSE : TRUE),
'isEven' => (0 === $cycle % 2 ? TRUE : FALSE),
'isFirst' => ($i === $from ? TRUE : FALSE),
'isLast' => $this->isLast($i, $from, $to, $step)
);
$this->templateVariableContainer->add($iterationArgument, $iteration);
$content = $this->renderChildren();
$this->templateVariableContainer->remove($iterationArgument);
} else {
$content = $this->renderChildren();
}
return $content;
}
/**
* @param integer $i
* @param integer $from
* @param integer $to
* @param integer $step
* @return boolean
*/
protected function isLast($i, $from, $to, $step) {
if ($from === $to) {
$isLast = TRUE;
} elseif ($from < $to) {
$isLast = ($i + $step > $to);
} else {
$isLast = ($i + $step < $to);
}
return $isLast;
}
}

View File

@@ -0,0 +1,67 @@
<?php
namespace FluidTYPO3\Vhs\ViewHelpers\Iterator;
/*
* This file is part of the FluidTYPO3/Vhs project under GPLv2 or later.
*
* For the full copyright and license information, please read the
* LICENSE.md file that was distributed with this source code.
*/
use FluidTYPO3\Vhs\Traits\ArrayConsumingViewHelperTrait;
use FluidTYPO3\Vhs\Traits\TemplateVariableViewHelperTrait;
use TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper;
/**
* Creates chunks from an input Array/Traversable with option to allocate items to a fixed number of chunks
*
* @author Benjamin Rau <rau@codearts.at>, codearts
* @package Vhs
* @subpackage ViewHelpers\Iterator
*/
class ChunkViewHelper extends AbstractViewHelper {
use TemplateVariableViewHelperTrait;
use ArrayConsumingViewHelperTrait;
/**
* @return void
*/
public function initializeArguments() {
$this->registerAsArgument();
$this->registerArgument('subject', 'mixed', 'The subject Traversable/Array instance to shift', FALSE, NULL);
}
/**
* Render method
*
* @param integer $count The count of items per chunk or if fixed number of chunks
* @param boolean $fixed Whether to allocate items to a fixed number of chunks or not
* @param boolean $preserveKeys If set to true, the original array keys will be preserved in the chunks
* @throws \Exception
* @return array
*/
public function render($count, $fixed = FALSE, $preserveKeys = FALSE) {
$subject = $this->getArgumentFromArgumentsOrTagContentAndConvertToArray('subject');
$output = array();
if (0 >= $count) {
return $output;
}
if (TRUE === (boolean) $fixed) {
$subjectSize = count($subject);
if (0 < $subjectSize) {
$chunkSize = ceil($subjectSize / $count);
$output = array_chunk($subject, $chunkSize, $preserveKeys);
}
// Fill the resulting array with empty items to get the desired element count
$elementCount = count($output);
if ($elementCount < $count) {
$output += array_fill($elementCount, $count - $elementCount, NULL);
}
} else {
$output = array_chunk($subject, $count, $preserveKeys);
}
return $this->renderChildrenWithVariableOrReturnInput($output);
}
}

View File

@@ -0,0 +1,78 @@
<?php
namespace FluidTYPO3\Vhs\ViewHelpers\Iterator;
/*
* This file is part of the FluidTYPO3/Vhs project under GPLv2 or later.
*
* For the full copyright and license information, please read the
* LICENSE.md file that was distributed with this source code.
*/
use FluidTYPO3\Vhs\Traits\BasicViewHelperTrait;
use FluidTYPO3\Vhs\Traits\TemplateVariableViewHelperTrait;
use TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper;
/**
* Explode ViewHelper
*
* Explodes a string by $glue
*
* @author Claus Due <claus@namelesscoder.net>
* @package Vhs
* @subpackage ViewHelpers\Iterator
*/
class ExplodeViewHelper extends AbstractViewHelper {
use BasicViewHelperTrait;
use TemplateVariableViewHelperTrait;
/**
* @var string
*/
protected $method = 'explode';
/**
* Initialize
*
* @return void
*/
public function initializeArguments() {
$this->registerAsArgument();
$this->registerArgument('content', 'string', 'String to be exploded by glue', FALSE, NULL);
$this->registerArgument('glue', 'string', 'String used as glue in the string to be exploded. Use glue value of "constant:NAMEOFCONSTANT" (fx "constant:LF" for linefeed as glue)', FALSE, ',');
}
/**
* Render method
*
* @return mixed
*/
public function render() {
$content = $this->getArgumentFromArgumentsOrTagContent('content');
$glue = $this->resolveGlue();
$output = call_user_func_array($this->method, array($glue, $content));
return $this->renderChildrenWithVariableOrReturnInput($output);
}
/**
* Detects the proper glue string to use for implode/explode operation
*
* @return string
*/
protected function resolveGlue() {
$glue = $this->arguments['glue'];
if (FALSE !== strpos($glue, ':') && 1 < strlen($glue)) {
// glue contains a special type identifier, resolve the actual glue
list ($type, $value) = explode(':', $glue);
switch ($type) {
case 'constant':
$glue = constant($value);
break;
default:
$glue = $value;
}
}
return $glue;
}
}

View File

@@ -0,0 +1,178 @@
<?php
namespace FluidTYPO3\Vhs\ViewHelpers\Iterator;
/*
* This file is part of the FluidTYPO3/Vhs project under GPLv2 or later.
*
* For the full copyright and license information, please read the
* LICENSE.md file that was distributed with this source code.
*/
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Reflection\ObjectAccess;
use TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper;
/**
* ### Iterator / Extract VieWHelper
*
* Loop through the iterator and extract a key, optionally join the
* results if more than one value is found.
*
* #### Extract values from an array by key
*
* The extbase version of indexed_search returns an array of the
* previous search, which cannot easily be shown in the input field
* of the result page. This can be solved.
*
* #### Input from extbase version of indexed_search">
*
* array(
* 0 => array(
* 'sword' => 'firstWord',
* 'oper' => 'AND'
* ),
* 1 => array(
* 'sword' => 'secondWord',
* 'oper' => 'AND'
* ),
* 3 => array(
* 'sword' => 'thirdWord',
* 'oper' => 'AND'
* )
* )
*
* Show the previous search words in the search form of the
* result page:
*
* #### Example
* <f:form.textfield name="search[sword]"
* value="{v:iterator.extract(key:'sword', content: searchWords) -> v:iterator.implode(glue: ' ')}"
* class="tx-indexedsearch-searchbox-sword" />
*
* #### Get the names of several users
*
* Provided we have a bunch of FrontendUsers and we need to show
* their firstname combined into a string:
*
* <h2>Welcome
* <v:iterator.implode glue=", "><v:iterator.extract key="firstname" content="frontendUsers" /></v:iterator.implode>
* <!-- alternative: -->
* {frontendUsers -> v:iterator.extract(key: 'firstname') -> v:iterator.implode(glue: ', ')}
* </h2>
*
* #### Output
*
* <h2>Welcome Peter, Paul, Marry</h2>
*
* #### Complex example
*
* {anArray->v:iterator.extract(path: 'childProperty.secondNestedChildObject')->v:iterator.sort(direction: 'DESC', sortBy: 'propertyOnSecondChild')->v:iterator.slice(length: 10)->v:iterator.extract(key: 'uid')}
*
* #### Single return value
*
* Outputs the "uid" value of the first record in variable $someRecords without caring if there are more than
* one records. Always extracts the first value and then stops. Equivalent of chaning -> v:iterator.first().
* {someRecords -> v:iterator.extract(key: 'uid', single: TRUE)}
*
* @author Andreas Lappe <nd@kaeufli.ch>
* @package Vhs
* @subpackage ViewHelpers\Iterator
*/
class ExtractViewHelper extends AbstractViewHelper {
/**
* @param string $key The name of the key from which you wish to extract the value
* @param mixed $content The array or Iterator that contains either the value or arrays of values
* @param boolean $recursive If TRUE, attempts to extract the key from deep nested arrays
* @param boolean $single If TRUE, returns only one value - always the first one - instead of an array of values
* @return array
*/
public function render($key, $content = NULL, $recursive = TRUE, $single = FALSE) {
if (NULL === $content) {
$content = $this->renderChildren();
}
try {
// extraction from Iterators could potentially use a getter method which throws
// exceptions - although this would be bad practice. Catch the exception here
// and turn it into a WARNING log message so that output does not break.
if (TRUE === (boolean) $recursive) {
$result = $this->recursivelyExtractKey($content, $key);
} else {
$result = $this->extractByKey($content, $key);
}
} catch (\Exception $error) {
GeneralUtility::sysLog($error->getMessage(), 'vhs', GeneralUtility::SYSLOG_SEVERITY_WARNING);
$result = array();
}
if (TRUE === (boolean) $single) {
return reset($result);
}
return $result;
}
/**
* Extract by key
*
* @param \Traversable $iterator
* @param string $key
* @return mixed NULL or whatever we found at $key
* @throws \Exception
*/
public function extractByKey($iterator, $key) {
if (FALSE === is_array($iterator) && FALSE === $iterator instanceof \Traversable) {
throw new \Exception('Traversable object or array expected but received ' . gettype($iterator), 1361532490);
}
$result = ObjectAccess::getPropertyPath($iterator, $key);
return $result;
}
/**
* Recursively extract the key
*
* @param \Traversable $iterator
* @param string $key
* @return string
* @throws \Exception
*/
public function recursivelyExtractKey($iterator, $key) {
$content = array();
foreach ($iterator as $v) {
// Lets see if we find something directly:
$result = ObjectAccess::getPropertyPath($v, $key);
if (NULL !== $result) {
$content[] = $result;
} elseif (TRUE === is_array($v) || TRUE === $v instanceof \Traversable) {
$content[] = $this->recursivelyExtractKey($v, $key);
}
}
$content = $this->flattenArray($content);
return $content;
}
/**
* Flatten the result structure, to iterate it cleanly in fluid
*
* @param array $content
* @param array $flattened
* @return array
*/
public function flattenArray(array $content, $flattened = NULL) {
foreach ($content as $sub) {
if (TRUE === is_array($sub)) {
$flattened = $this->flattenArray($sub, $flattened);
} else {
$flattened[] = $sub;
}
}
return $flattened;
}
}

View File

@@ -0,0 +1,85 @@
<?php
namespace FluidTYPO3\Vhs\ViewHelpers\Iterator;
/*
* This file is part of the FluidTYPO3/Vhs project under GPLv2 or later.
*
* For the full copyright and license information, please read the
* LICENSE.md file that was distributed with this source code.
*/
use TYPO3\CMS\Extbase\Reflection\ObjectAccess;
use TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper;
/**
* ### Iterator: Filter ViewHelper
*
* Filters an array by filtering the array, analysing each member
* and assering if it is equal to (weak type) the `filter` parameter.
* If `propertyName` is set, the ViewHelper will try to extract this
* property from each member of the array.
*
* Iterators and ObjectStorage etc. are supported.
*
* @author Claus Due <claus@namelesscoder.net>
* @package Vhs
* @subpackage ViewHelpers\Iterator
*/
class FilterViewHelper extends AbstractViewHelper {
/**
* Render method
*
* @param mixed $subject The subject iterator/array to be filtered
* @param mixed $filter The comparison value
* @param string $propertyName Optional property name to extract and use for comparison instead of the object; use on ObjectStorage etc. Note: supports dot-path expressions.
* @param boolean $preserveKeys If TRUE, keys in the array are preserved - even if they are numeric
* @param boolean $invert Invert the behavior of the view helper
* @param boolean $nullFilter If TRUE and $filter is NULL (not set) - to filter NULL or empty values
*
* @return mixed
*/
public function render($subject = NULL, $filter = NULL, $propertyName = NULL, $preserveKeys = FALSE, $invert = FALSE, $nullFilter = FALSE) {
if (NULL === $subject) {
$subject = $this->renderChildren();
}
if (NULL === $subject || (FALSE === is_array($subject) && FALSE === $subject instanceof \Traversable)) {
return array();
}
if ((FALSE === (boolean) $nullFilter && NULL === $filter) || '' === $filter) {
return $subject;
}
if (TRUE === $subject instanceof \Traversable) {
$subject = iterator_to_array($subject);
}
$items = array();
$invert = (boolean) $invert;
$invertFlag = TRUE === $invert ? FALSE : TRUE;
foreach ($subject as $key => $item) {
if ($invertFlag === $this->filter($item, $filter, $propertyName)) {
$items[$key] = $item;
}
}
return TRUE === $preserveKeys ? $items : array_values($items);
}
/**
* Filter an item/value according to desired filter. Returns TRUE if
* the item should be included, FALSE otherwise. This default method
* simply does a weak comparison (==) for sameness.
*
* @param mixed $item
* @param mixed $filter Could be a single value or an Array. If so the function returns TRUE when $item matches with any value in it.
* @param string $propertyName
* @return boolean
*/
protected function filter($item, $filter, $propertyName) {
if (FALSE === empty($propertyName) && (TRUE === is_object($item) || TRUE === is_array($item))) {
$value = ObjectAccess::getPropertyPath($item, $propertyName);
} else {
$value = $item;
}
return is_array($filter) ? in_array($value, $filter) : ($value == $filter);
}
}

View File

@@ -0,0 +1,56 @@
<?php
namespace FluidTYPO3\Vhs\ViewHelpers\Iterator;
/*
* This file is part of the FluidTYPO3/Vhs project under GPLv2 or later.
*
* For the full copyright and license information, please read the
* LICENSE.md file that was distributed with this source code.
*/
use TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper;
use TYPO3\CMS\Fluid\Core\ViewHelper\Exception;
/**
* Returns the first element of $haystack
*
* @author Claus Due
* @package Vhs
* @subpackage ViewHelpers\Iterator
*/
class FirstViewHelper extends AbstractViewHelper {
/**
* Initialize arguments
*
* @return void
*/
public function initializeArguments() {
$this->registerArgument('haystack', 'mixed', 'Haystack in which to look for needle', FALSE, NULL);
}
/**
* Render method
*
* @throws Exception
* @return mixed|NULL
*/
public function render() {
$haystack = $this->arguments['haystack'];
if (NULL === $haystack) {
$haystack = $this->renderChildren();
}
if (FALSE === is_array($haystack) && FALSE === $haystack instanceof \Iterator && NULL !== $haystack) {
throw new Exception('Invalid argument supplied to Iterator/FirstViewHelper - expected array, Iterator or NULL but got ' .
gettype($haystack), 1351958398);
}
if (NULL === $haystack) {
return NULL;
}
foreach ($haystack as $needle) {
return $needle;
}
return NULL;
}
}

View File

@@ -0,0 +1,78 @@
<?php
namespace FluidTYPO3\Vhs\ViewHelpers\Iterator;
/*
* This file is part of the FluidTYPO3/Vhs project under GPLv2 or later.
*
* For the full copyright and license information, please read the
* LICENSE.md file that was distributed with this source code.
*/
/**
* Repeats rendering of children with a typical for loop: starting at
* index $from it will loop until the index has reached $to.
*
* @author Danilo Bürger <danilo.buerger@hmspl.de>, Heimspiel GmbH
* @package Vhs
* @subpackage ViewHelpers\Iterator
*/
class ForViewHelper extends AbstractLoopViewHelper {
/**
* @return void
*/
public function initializeArguments() {
parent::initializeArguments();
$this->registerArgument('to', 'integer', 'Number that the index needs to reach before stopping', TRUE);
$this->registerArgument('from', 'integer', 'Starting number for the index', FALSE, 0);
$this->registerArgument('step', 'integer', 'Stepping number that the index is increased by after each loop', FALSE, 1);
}
/**
* @throws \RuntimeException
* @return string
*/
public function render() {
$to = intval($this->arguments['to']);
$from = intval($this->arguments['from']);
$step = intval($this->arguments['step']);
$iteration = $this->arguments['iteration'];
$content = '';
if (0 === $step) {
throw new \RuntimeException('"step" may not be 0.', 1383267698);
}
if ($from < $to && 0 > $step) {
throw new \RuntimeException('"step" must be greater than 0 if "from" is smaller than "to".', 1383268407);
}
if ($from > $to && 0 < $step) {
throw new \RuntimeException('"step" must be smaller than 0 if "from" is greater than "to".', 1383268415);
}
if (TRUE === $this->templateVariableContainer->exists($iteration)) {
$backupVariable = $this->templateVariableContainer->get($iteration);
$this->templateVariableContainer->remove($iteration);
}
if ($from === $to) {
$content = $this->renderIteration($from, $from, $to, $step, $iteration);
} elseif ($from < $to) {
for ($i = $from; $i <= $to; $i += $step) {
$content .= $this->renderIteration($i, $from, $to, $step, $iteration);
}
} else {
for ($i = $from; $i >= $to; $i += $step) {
$content .= $this->renderIteration($i, $from, $to, $step, $iteration);
}
}
if (TRUE === isset($backupVariable)) {
$this->templateVariableContainer->add($iteration, $backupVariable);
}
return $content;
}
}

View File

@@ -0,0 +1,27 @@
<?php
namespace FluidTYPO3\Vhs\ViewHelpers\Iterator;
/*
* This file is part of the FluidTYPO3/Vhs project under GPLv2 or later.
*
* For the full copyright and license information, please read the
* LICENSE.md file that was distributed with this source code.
*/
/**
* Implode ViewHelper
*
* Implodes an array or array-convertible object by $glue
*
* @author Claus Due
* @package Vhs
* @subpackage ViewHelpers\Iterator
*/
class ImplodeViewHelper extends ExplodeViewHelper {
/**
* @var string
*/
protected $method = 'implode';
}

View File

@@ -0,0 +1,54 @@
<?php
namespace FluidTYPO3\Vhs\ViewHelpers\Iterator;
/*
* This file is part of the FluidTYPO3/Vhs project under GPLv2 or later.
*
* For the full copyright and license information, please read the
* LICENSE.md file that was distributed with this source code.
*/
use FluidTYPO3\Vhs\ViewHelpers\Condition\Iterator\ContainsViewHelper;
use TYPO3\CMS\Fluid\Core\Rendering\RenderingContextInterface;
/**
* Searches $haystack for index of $needle, returns -1 if $needle
* is not in $haystack
*
* @author Claus Due
* @package Vhs
* @subpackage ViewHelpers\Iterator
*/
class IndexOfViewHelper extends ContainsViewHelper {
/**
* Render
*
* @return string
*/
public function render() {
return static::renderStatic(
$this->arguments,
$this->buildRenderChildrenClosure(),
$this->renderingContext
);
}
/**
* Default implementation for use in compiled templates
*
* @param array $arguments
* @param \Closure $renderChildrenClosure
* @param RenderingContextInterface $renderingContext
* @return mixed
*/
static public function renderStatic(array $arguments, \Closure $renderChildrenClosure, RenderingContextInterface $renderingContext) {
$evaluation = self::assertHaystackHasNeedle($arguments['haystack'], $arguments['needle'], $arguments);
if (FALSE !== $evaluation) {
return intval($evaluation);
}
return -1;
}
}

View File

@@ -0,0 +1,52 @@
<?php
namespace FluidTYPO3\Vhs\ViewHelpers\Iterator;
/*
* This file is part of the FluidTYPO3/Vhs project under GPLv2 or later.
*
* For the full copyright and license information, please read the
* LICENSE.md file that was distributed with this source code.
*/
use FluidTYPO3\Vhs\Traits\ArrayConsumingViewHelperTrait;
use TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper;
/**
* Intersects arrays/Traversables $a and $b into an array
*
* @author Danilo Bürger <danilo.buerger@hmspl.de>, Heimspiel GmbH
* @package Vhs
* @subpackage ViewHelpers\Iterator
*/
class IntersectViewHelper extends AbstractViewHelper {
use ArrayConsumingViewHelperTrait;
/**
* Initialize
*
* @return void
*/
public function initializeArguments() {
parent::initializeArguments();
$this->registerArgument('a', 'mixed', 'First Array/Traversable/CSV', FALSE, NULL);
$this->registerArgument('b', 'mixed', 'Second Array/Traversable/CSV', TRUE);
}
/**
* @return array
*/
public function render() {
$a = $this->arguments['a'];
if (NULL === $a) {
$a = $this->renderChildren();
}
$a = $this->arrayFromArrayOrTraversableOrCSV($a);
$b = $this->arrayFromArrayOrTraversableOrCSV($this->arguments['b']);
return array_intersect($a, $b);
}
}

View File

@@ -0,0 +1,46 @@
<?php
namespace FluidTYPO3\Vhs\ViewHelpers\Iterator;
/*
* This file is part of the FluidTYPO3/Vhs project under GPLv2 or later.
*
* For the full copyright and license information, please read the
* LICENSE.md file that was distributed with this source code.
*/
use FluidTYPO3\Vhs\Traits\ArrayConsumingViewHelperTrait;
use FluidTYPO3\Vhs\Traits\TemplateVariableViewHelperTrait;
use FluidTYPO3\Vhs\Traits\VhsViewHelperTrait;
use TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper;
/**
* Gets keys from an iterator
*
* @author Claus Due <claus@namelesscoder.net>
* @author Stefan Neufeind <info (at) speedpartner.de>
* @package Vhs
* @subpackage ViewHelpers\Iterator
*/
class KeysViewHelper extends AbstractViewHelper {
use TemplateVariableViewHelperTrait;
use ArrayConsumingViewHelperTrait;
/**
* @return void
*/
public function initializeArguments() {
$this->registerAsArgument();
$this->registerArgument('subject', 'mixed', 'Input to work on - Array/Traversable/...', FALSE, NULL);
}
/**
* @return array
*/
public function render() {
$subject = $this->getArgumentFromArgumentsOrTagContentAndConvertToArray('subject');
$content = array_keys($subject);
return $this->renderChildrenWithVariableOrReturnInput($content);
}
}

View File

@@ -0,0 +1,49 @@
<?php
namespace FluidTYPO3\Vhs\ViewHelpers\Iterator;
/*
* This file is part of the FluidTYPO3/Vhs project under GPLv2 or later.
*
* For the full copyright and license information, please read the
* LICENSE.md file that was distributed with this source code.
*/
use FluidTYPO3\Vhs\Traits\ArrayConsumingViewHelperTrait;
use TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper;
/**
* Returns the last element of $haystack
*
* @author Claus Due
* @package Vhs
* @subpackage ViewHelpers\Iterator
*/
class LastViewHelper extends AbstractViewHelper {
use ArrayConsumingViewHelperTrait;
/**
* Initialize arguments
*
* @return void
*/
public function initializeArguments() {
$this->registerArgument('haystack', 'mixed', 'Haystack in which to look for needle', FALSE, NULL);
}
/**
* Render method
*
* @return mixed|NULL
*/
public function render() {
$haystack = $this->arguments['haystack'];
if (NULL === $haystack) {
$haystack = $this->renderChildren();
}
$haystack = $this->arrayFromArrayOrTraversableOrCSV($haystack);
return array_pop($haystack);
}
}

View File

@@ -0,0 +1,77 @@
<?php
namespace FluidTYPO3\Vhs\ViewHelpers\Iterator;
/*
* This file is part of the FluidTYPO3/Vhs project under GPLv2 or later.
*
* For the full copyright and license information, please read the
* LICENSE.md file that was distributed with this source code.
*/
/**
* Repeats rendering of children $count times while updating $iteration
*
* @author Danilo Bürger <danilo.buerger@hmspl.de>, Heimspiel GmbH
* @author Claus Due <claus@namelesscoder.net>
* @package Vhs
* @subpackage ViewHelpers\Iterator
*/
class LoopViewHelper extends AbstractLoopViewHelper {
/**
* Initialize
*
* @return void
*/
public function initializeArguments() {
parent::initializeArguments();
$this->registerArgument('count', 'integer', 'Number of times to render child content', TRUE);
$this->registerArgument('minimum', 'integer', 'Minimum number of loops before stopping', FALSE, 0);
$this->registerArgument('maximum', 'integer', 'Maxiumum number of loops before stopping', FALSE, PHP_INT_MAX);
}
/**
* @return string
*/
public function render() {
$count = intval($this->arguments['count']);
$minimum = intval($this->arguments['minimum']);
$maximum = intval($this->arguments['maximum']);
$iteration = $this->arguments['iteration'];
$content = '';
if ($count < $minimum) {
$count = $minimum;
} elseif ($count > $maximum) {
$count = $maximum;
}
if (TRUE === $this->templateVariableContainer->exists($iteration)) {
$backupVariable = $this->templateVariableContainer->get($iteration);
$this->templateVariableContainer->remove($iteration);
}
for ($i = 0; $i < $count; $i++) {
$content .= $this->renderIteration($i, 0, $count, 1, $iteration);
}
if (TRUE === isset($backupVariable)) {
$this->templateVariableContainer->add($iteration, $backupVariable);
}
return $content;
}
/**
* @param integer $i
* @param integer $from
* @param integer $to
* @param integer $step
* @return boolean
*/
protected function isLast($i, $from, $to, $step) {
return ($i + $step >= $to);
}
}

View File

@@ -0,0 +1,46 @@
<?php
namespace FluidTYPO3\Vhs\ViewHelpers\Iterator;
/*
* This file is part of the FluidTYPO3/Vhs project under GPLv2 or later.
*
* For the full copyright and license information, please read the
* LICENSE.md file that was distributed with this source code.
*/
use FluidTYPO3\Vhs\Traits\ArrayConsumingViewHelperTrait;
use TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper;
/**
* Merges arrays/Traversables $a and $b into an array
*
* @author Claus Due <claus@namelesscoder.net>
* @package Vhs
* @subpackage ViewHelpers\Iterator
*/
class MergeViewHelper extends AbstractViewHelper {
use ArrayConsumingViewHelperTrait;
/**
* @return void
*/
public function initializeArguments() {
$this->registerArgument('a', 'mixed', 'First array/Traversable - if not set, the ViewHelper can be in a chain (inline-notation)', FALSE, NULL);
}
/**
* Merges arrays/Traversables $a and $b into an array
*
* @param mixed $b Second array/Traversable
* @param boolean $useKeys If TRUE, comparison is done while also observing (and merging) the keys used in each array
* @return array
*/
public function render($b, $useKeys = TRUE) {
$a = $this->getArgumentFromArgumentsOrTagContentAndConvertToArray('a');
$b = $this->arrayFromArrayOrTraversableOrCSV($b, $useKeys);
$merged = $this->mergeArrays($a, $b);
return $merged;
}
}

View File

@@ -0,0 +1,49 @@
<?php
namespace FluidTYPO3\Vhs\ViewHelpers\Iterator;
/*
* This file is part of the FluidTYPO3/Vhs project under GPLv2 or later.
*
* For the full copyright and license information, please read the
* LICENSE.md file that was distributed with this source code.
*/
use FluidTYPO3\Vhs\ViewHelpers\Condition\Iterator\ContainsViewHelper;
use TYPO3\CMS\Fluid\Core\Rendering\RenderingContextInterface;
/**
* Returns next element in array $haystack from position of $needle
*
* @author Claus Due <claus@namelesscoder.net>
* @package Vhs
* @subpackage ViewHelpers\Iterator
*/
class NextViewHelper extends ContainsViewHelper {
/**
* Render
*
* @return string
*/
public function render() {
return static::renderStatic(
$this->arguments,
$this->buildRenderChildrenClosure(),
$this->renderingContext
);
}
/**
* Default implementation for use in compiled templates
*
* @param array $arguments
* @param \Closure $renderChildrenClosure
* @param RenderingContextInterface $renderingContext
* @return mixed
*/
static public function renderStatic(array $arguments, \Closure $renderChildrenClosure, RenderingContextInterface $renderingContext) {
$evaluation = self::assertHaystackHasNeedle($arguments['haystack'], $arguments['needle'], $arguments);
return self::getNeedleAtIndex($evaluation !== FALSE ? $evaluation + 1 : -1, $arguments);
}
}

View File

@@ -0,0 +1,46 @@
<?php
namespace FluidTYPO3\Vhs\ViewHelpers\Iterator;
/*
* This file is part of the FluidTYPO3/Vhs project under GPLv2 or later.
*
* For the full copyright and license information, please read the
* LICENSE.md file that was distributed with this source code.
*/
use FluidTYPO3\Vhs\Traits\ArrayConsumingViewHelperTrait;
use FluidTYPO3\Vhs\Traits\TemplateVariableViewHelperTrait;
use TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper;
use TYPO3\CMS\Fluid\Core\ViewHelper\Exception;
/**
* Pops the last value off $subject (but does not change $subject itself as array_pop would)
*
* @author Claus Due <claus@namelesscoder.net>
* @package Vhs
* @subpackage ViewHelpers\Iterator
*/
class PopViewHelper extends AbstractViewHelper {
use TemplateVariableViewHelperTrait;
use ArrayConsumingViewHelperTrait;
/**
* @return void
*/
public function initializeArguments() {
$this->registerAsArgument();
$this->registerArgument('subject', 'mixed', 'Input to work on - Array/Traversable/...', FALSE, NULL);
}
/**
* @return mixed
*/
public function render() {
$subject = $this->getArgumentFromArgumentsOrTagContentAndConvertToArray('subject');
$output = array_pop($subject);
return $this->renderChildrenWithVariableOrReturnInput($output);
}
}

View File

@@ -0,0 +1,49 @@
<?php
namespace FluidTYPO3\Vhs\ViewHelpers\Iterator;
/*
* This file is part of the FluidTYPO3/Vhs project under GPLv2 or later.
*
* For the full copyright and license information, please read the
* LICENSE.md file that was distributed with this source code.
*/
use FluidTYPO3\Vhs\ViewHelpers\Condition\Iterator\ContainsViewHelper;
use TYPO3\CMS\Fluid\Core\Rendering\RenderingContextInterface;
/**
* Returns previous element in array $haystack from position of $needle
*
* @author Claus Due <claus@namelesscoder.net>
* @package Vhs
* @subpackage ViewHelpers\Iterator
*/
class PreviousViewHelper extends ContainsViewHelper {
/**
* Render
*
* @return string
*/
public function render() {
return static::renderStatic(
$this->arguments,
$this->buildRenderChildrenClosure(),
$this->renderingContext
);
}
/**
* Default implementation for use in compiled templates
*
* @param array $arguments
* @param \Closure $renderChildrenClosure
* @param RenderingContextInterface $renderingContext
* @return mixed
*/
static public function renderStatic(array $arguments, \Closure $renderChildrenClosure, RenderingContextInterface $renderingContext) {
$evaluation = self::assertHaystackHasNeedle($arguments['haystack'], $arguments['needle'], $arguments);
return self::getNeedleAtIndex($evaluation !== FALSE ? $evaluation - 1 : -1, $arguments);
}
}

View File

@@ -0,0 +1,48 @@
<?php
namespace FluidTYPO3\Vhs\ViewHelpers\Iterator;
/*
* This file is part of the FluidTYPO3/Vhs project under GPLv2 or later.
*
* For the full copyright and license information, please read the
* LICENSE.md file that was distributed with this source code.
*/
use FluidTYPO3\Vhs\Traits\ArrayConsumingViewHelperTrait;
use FluidTYPO3\Vhs\Traits\TemplateVariableViewHelperTrait;
use TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper;
use TYPO3\CMS\Fluid\Core\ViewHelper\Exception;
/**
* Returns random element from array
*
* @author Björn Fromme, <fromme@dreipunktnull.com>, dreipunktnull
* @package Vhs
* @subpackage ViewHelpers\Iterator
*/
class RandomViewHelper extends AbstractViewHelper {
use TemplateVariableViewHelperTrait;
use ArrayConsumingViewHelperTrait;
/**
* @return void
*/
public function initializeArguments() {
$this->registerAsArgument();
$this->registerArgument('subject', 'mixed', 'The subject Traversable/Array instance from which to select a random element', FALSE, NULL);
}
/**
* Render method
*
* @throws Exception
* @return mixed
*/
public function render() {
$subject = $this->getArgumentFromArgumentsOrTagContentAndConvertToArray('subject');
$randomElement = $subject[array_rand($subject)];
return $this->renderChildrenWithVariableOrReturnInput($randomElement);
}
}

View File

@@ -0,0 +1,57 @@
<?php
namespace FluidTYPO3\Vhs\ViewHelpers\Iterator;
/*
* This file is part of the FluidTYPO3/Vhs project under GPLv2 or later.
*
* For the full copyright and license information, please read the
* LICENSE.md file that was distributed with this source code.
*/
use FluidTYPO3\Vhs\Traits\ArrayConsumingViewHelperTrait;
use FluidTYPO3\Vhs\Traits\TemplateVariableViewHelperTrait;
use TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper;
use TYPO3\CMS\Fluid\Core\ViewHelper\Exception;
/**
* ### Iterator Reversal ViewHelper
*
* Reverses the order of every member of an Iterator/Array,
* preserving the original keys.
*
* @author Claus Due <claus@namelesscoder.net>
* @package Vhs
* @subpackage ViewHelpers\Iterator
*/
class ReverseViewHelper extends AbstractViewHelper {
use TemplateVariableViewHelperTrait;
use ArrayConsumingViewHelperTrait;
/**
* Initialize arguments
*
* @return void
*/
public function initializeArguments() {
$this->registerAsArgument();
$this->registerArgument('subject', 'mixed', 'The input array/Traversable to reverse', FALSE, NULL);
}
/**
* "Render" method - sorts a target list-type target. Either $array or
* $objectStorage must be specified. If both are, ObjectStorage takes precedence.
*
* Returns the same type as $subject. Ignores NULL values which would be
* OK to use in an f:for (empty loop as result)
*
* @throws \Exception
* @return mixed
*/
public function render() {
$array = $this->getArgumentFromArgumentsOrTagContentAndConvertToArray('subject');
$array = array_reverse($array, TRUE);
return $this->renderChildrenWithVariableOrReturnInput($array);
}
}

View File

@@ -0,0 +1,49 @@
<?php
namespace FluidTYPO3\Vhs\ViewHelpers\Iterator;
/*
* This file is part of the FluidTYPO3/Vhs project under GPLv2 or later.
*
* For the full copyright and license information, please read the
* LICENSE.md file that was distributed with this source code.
*/
use FluidTYPO3\Vhs\Traits\ArrayConsumingViewHelperTrait;
use FluidTYPO3\Vhs\Traits\TemplateVariableViewHelperTrait;
use TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper;
use TYPO3\CMS\Fluid\Core\ViewHelper\Exception;
/**
* Shifts the first value off $subject (but does not change $subject itself as array_shift would)
*
* @author Claus Due <claus@namelesscoder.net>
* @package Vhs
* @subpackage ViewHelpers\Iterator
*/
class ShiftViewHelper extends AbstractViewHelper {
use TemplateVariableViewHelperTrait;
use ArrayConsumingViewHelperTrait;
/**
* Initialize arguments
*
* @return void
*/
public function initializeArguments() {
$this->registerAsArgument();
$this->registerArgument('subject', 'mixed', 'The input array/Traversable to shift', FALSE, NULL);
}
/**
* Render method
*
* @return mixed
*/
public function render() {
$subject = $this->getArgumentFromArgumentsOrTagContentAndConvertToArray('subject');
$output = array_shift($subject);
return $this->renderChildrenWithVariableOrReturnInput($output);
}
}

View File

@@ -0,0 +1,51 @@
<?php
namespace FluidTYPO3\Vhs\ViewHelpers\Iterator;
/*
* This file is part of the FluidTYPO3/Vhs project under GPLv2 or later.
*
* For the full copyright and license information, please read the
* LICENSE.md file that was distributed with this source code.
*/
use FluidTYPO3\Vhs\Traits\ArrayConsumingViewHelperTrait;
use FluidTYPO3\Vhs\Traits\TemplateVariableViewHelperTrait;
use TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper;
use TYPO3\CMS\Fluid\Core\ViewHelper\Exception;
/**
* Slice an Iterator by $start and $length
*
* @author Claus Due <claus@namelesscoder.net>
* @package Vhs
* @subpackage ViewHelpers\Iterator
*/
class SliceViewHelper extends AbstractViewHelper {
use TemplateVariableViewHelperTrait;
use ArrayConsumingViewHelperTrait;
/**
* Initialize arguments
*
* @return void
*/
public function initializeArguments() {
$this->registerAsArgument();
$this->registerArgument('haystack', 'mixed', 'The input array/Traversable to reverse', FALSE, NULL);
}
/**
* Render method
*
* @param integer $start
* @param integer $length
* @return array
*/
public function render($start = 0, $length = NULL) {
$haystack = $this->getArgumentFromArgumentsOrTagContentAndConvertToArray('haystack');
$output = array_slice($haystack, $start, $length, TRUE);
return $this->renderChildrenWithVariableOrReturnInput($output);
}
}

View File

@@ -0,0 +1,199 @@
<?php
namespace FluidTYPO3\Vhs\ViewHelpers\Iterator;
/*
* This file is part of the FluidTYPO3/Vhs project under GPLv2 or later.
*
* For the full copyright and license information, please read the
* LICENSE.md file that was distributed with this source code.
*/
use FluidTYPO3\Vhs\Traits\ArrayConsumingViewHelperTrait;
use FluidTYPO3\Vhs\Traits\BasicViewHelperTrait;
use FluidTYPO3\Vhs\Traits\TemplateVariableViewHelperTrait;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Object\ObjectManager;
use TYPO3\CMS\Extbase\Persistence\Generic\LazyObjectStorage;
use TYPO3\CMS\Extbase\Persistence\ObjectStorage;
use TYPO3\CMS\Extbase\Persistence\QueryResultInterface;
use TYPO3\CMS\Extbase\Reflection\ObjectAccess;
use TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper;
use TYPO3\CMS\Fluid\Core\ViewHelper\Exception;
/**
* Sorts an instance of ObjectStorage, an Iterator implementation,
* an Array or a QueryResult (including Lazy counterparts).
*
* Can be used inline, i.e.:
* <f:for each="{dataset -> vhs:iterator.sort(sortBy: 'name')}" as="item">
* // iterating data which is ONLY sorted while rendering this particular loop
* </f:for>
*
* @author Claus Due <claus@namelesscoder.net>
* @package Vhs
* @subpackage ViewHelpers\Iterator
*/
class SortViewHelper extends AbstractViewHelper {
use BasicViewHelperTrait;
use TemplateVariableViewHelperTrait;
use ArrayConsumingViewHelperTrait;
/**
* Contains all flags that are allowed to be used
* with the sorting functions
*
* @var array
*/
protected $allowedSortFlags = array(
'SORT_REGULAR',
'SORT_STRING',
'SORT_NUMERIC',
'SORT_NATURAL',
'SORT_LOCALE_STRING',
'SORT_FLAG_CASE'
);
/**
* Initialize arguments
*
* @return void
*/
public function initializeArguments() {
$this->registerAsArgument();
$this->registerArgument('subject', 'mixed', 'The array/Traversable instance to sort', FALSE, NULL);
$this->registerArgument('sortBy', 'string', 'Which property/field to sort by - leave out for numeric sorting based on indexes(keys)');
$this->registerArgument('order', 'string', 'ASC, DESC, RAND or SHUFFLE. RAND preserves keys, SHUFFLE does not - but SHUFFLE is faster', FALSE, 'ASC');
$this->registerArgument('sortFlags', 'string', 'Constant name from PHP for `SORT_FLAGS`: `SORT_REGULAR`, `SORT_STRING`, `SORT_NUMERIC`, `SORT_NATURAL`, `SORT_LOCALE_STRING` or `SORT_FLAG_CASE`. You can provide a comma seperated list or array to use a combination of flags.', FALSE, 'SORT_REGULAR');
}
/**
* "Render" method - sorts a target list-type target. Either $array or
* $objectStorage must be specified. If both are, ObjectStorage takes precedence.
*
* Returns the same type as $subject. Ignores NULL values which would be
* OK to use in an f:for (empty loop as result)
* @return mixed
* @throws \Exception
*/
public function render() {
$subject = $this->getArgumentFromArgumentsOrTagContent('subject');
$sorted = NULL;
if (TRUE === is_array($subject)) {
$sorted = $this->sortArray($subject);
} else {
if (TRUE === $subject instanceof ObjectStorage || TRUE === $subject instanceof LazyObjectStorage) {
$sorted = $this->sortObjectStorage($subject);
} elseif (TRUE === $subject instanceof \Iterator) {
/** @var \Iterator $subject */
$array = iterator_to_array($subject, TRUE);
$sorted = $this->sortArray($array);
} elseif (TRUE === $subject instanceof QueryResultInterface) {
/** @var QueryResultInterface $subject */
$sorted = $this->sortArray($subject->toArray());
} elseif (NULL !== $subject) {
// a NULL value is respected and ignored, but any
// unrecognized value other than this is considered a
// fatal error.
throw new \Exception('Unsortable variable type passed to Iterator/SortViewHelper. Expected any of Array, QueryResult, ' .
' ObjectStorage or Iterator implementation but got ' . gettype($subject), 1351958941);
}
}
return $this->renderChildrenWithVariableOrReturnInput($sorted);
}
/**
* Sort an array
*
* @param array|\Iterator $array
* @return array
*/
protected function sortArray($array) {
$sorted = array();
foreach ($array as $index => $object) {
if (TRUE === isset($this->arguments['sortBy'])) {
$index = $this->getSortValue($object);
}
while (isset($sorted[$index])) {
$index .= '.1';
}
$sorted[$index] = $object;
}
if ('ASC' === $this->arguments['order']) {
ksort($sorted, $this->getSortFlags());
} elseif ('RAND' === $this->arguments['order']) {
$sortedKeys = array_keys($sorted);
shuffle($sortedKeys);
$backup = $sorted;
$sorted = array();
foreach ($sortedKeys as $sortedKey) {
$sorted[$sortedKey] = $backup[$sortedKey];
}
} elseif ('SHUFFLE' === $this->arguments['order']) {
shuffle($sorted);
} else {
krsort($sorted, $this->getSortFlags());
}
return $sorted;
}
/**
* Sort an ObjectStorage instance
*
* @param ObjectStorage $storage
* @return ObjectStorage
*/
protected function sortObjectStorage($storage) {
/** @var ObjectManager $objectManager */
$objectManager = GeneralUtility::makeInstance('TYPO3\\CMS\\Extbase\\Object\\ObjectManager');
/** @var ObjectStorage $temp */
$temp = $objectManager->get('TYPO3\\CMS\\Extbase\\Persistence\\ObjectStorage');
foreach ($storage as $item) {
$temp->attach($item);
}
$sorted = $this->sortArray($storage);
$storage = $objectManager->get('TYPO3\\CMS\\Extbase\\Persistence\\ObjectStorage');
foreach ($sorted as $item) {
$storage->attach($item);
}
return $storage;
}
/**
* Gets the value to use as sorting value from $object
*
* @param mixed $object
* @return mixed
*/
protected function getSortValue($object) {
$field = $this->arguments['sortBy'];
$value = ObjectAccess::getPropertyPath($object, $field);
if (TRUE === $value instanceof \DateTime) {
$value = intval($value->format('U'));
} elseif (TRUE === $value instanceof ObjectStorage || TRUE === $value instanceof LazyObjectStorage) {
$value = $value->count();
} elseif (is_array($value)) {
$value = count($value);
}
return $value;
}
/**
* Parses the supplied flags into the proper value for the sorting
* function.
* @return int
* @throws Exception
*/
protected function getSortFlags() {
$constants = $this->arrayFromArrayOrTraversableOrCSV($this->arguments['sortFlags']);
$flags = 0;
foreach ($constants as $constant) {
if (FALSE === in_array($constant, $this->allowedSortFlags)) {
throw new Exception('The constant "' . $constant . '" you\'re trying to use as a sortFlag is not allowed. Allowed constants are: ' . implode(', ', $this->allowedSortFlags) . '.', 1404220538);
}
$flags = $flags | constant(trim($constant));
}
return $flags;
}
}

View File

@@ -0,0 +1,66 @@
<?php
namespace FluidTYPO3\Vhs\ViewHelpers\Iterator;
/***************************************************************
* Copyright notice
*
* (c) 2014 Claus Due <claus@namelesscoder.net>
*
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/
use FluidTYPO3\Vhs\Traits\ArrayConsumingViewHelperTrait;
use FluidTYPO3\Vhs\Traits\TemplateVariableViewHelperTrait;
use TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper;
use TYPO3\CMS\Fluid\Core\ViewHelper\Exception;
/**
* Gets values from an iterator, removing current keys (if any exist)
*
* @author Claus Due <claus@namelesscoder.net>
* @package Vhs
* @subpackage ViewHelpers\Iterator
*/
class ValuesViewHelper extends AbstractViewHelper {
use TemplateVariableViewHelperTrait;
use ArrayConsumingViewHelperTrait;
/**
* Initialize arguments
*
* @return void
*/
public function initializeArguments() {
$this->registerAsArgument();
$this->registerArgument('subject', 'mixed', 'The array/Traversable instance from which to get values', FALSE, NULL);
}
/**
* Render method
*
* @return array
*/
public function render() {
$subject = $this->getArgumentFromArgumentsOrTagContentAndConvertToArray('subject');
$output = array_values($subject);
return $this->renderChildrenWithVariableOrReturnInput($output);
}
}