/modules/kotal/vendor/phptal/PHPTAL/RepeatController.php
PHP | 321 lines | 187 code | 32 blank | 102 comment | 17 complexity | 3721a3b91c394ff44921ed26a4bfb101 MD5 | raw file
Possible License(s): LGPL-2.1, MIT, BSD-3-Clause
- <?php
- /**
- * PHPTAL templating engine
- *
- * PHP Version 5
- *
- * @category HTML
- * @package PHPTAL
- * @author Laurent Bedubourg <lbedubourg@motion-twin.com>
- * @author Kornel LesiĹski <kornel@aardvarkmedia.co.uk>
- * @author IvĂĄn Montes <drslump@pollinimini.net>
- * @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License
- * @version SVN: $Id$
- * @link http://phptal.org/
- */
- /**
- * Stores tal:repeat information during template execution.
- *
- * An instance of this class is created and stored into PHPTAL context on each
- * tal:repeat usage.
- *
- * repeat/item/index
- * repeat/item/number
- * ...
- * are provided by this instance.
- *
- * 'repeat' is an stdClass instance created to handle RepeatControllers,
- * 'item' is an instance of this class.
- *
- * @package PHPTAL
- * @subpackage Php
- * @author Laurent Bedubourg <lbedubourg@motion-twin.com>
- */
- class PHPTAL_RepeatController implements Iterator
- {
- public $key;
- private $current;
- private $valid;
- private $validOnNext;
- private $uses_groups = false;
- protected $iterator;
- public $index;
- public $end;
- /**
- * computed lazily
- */
- private $length = null;
- /**
- * Construct a new RepeatController.
- *
- * @param $source array, string, iterator, iterable.
- */
- public function __construct($source)
- {
- if ( is_string($source) ) {
- $this->iterator = new ArrayIterator( str_split($source) ); // FIXME: invalid for UTF-8 encoding, use preg_match_all('/./u') trick
- } elseif ( is_array($source) ) {
- $this->iterator = new ArrayIterator($source);
- } elseif ($source instanceof IteratorAggregate) {
- $this->iterator = $source->getIterator();
- } elseif ($source instanceof DOMNodeList) {
- $array = array();
- foreach ($source as $k=>$v) {
- $array[$k] = $v;
- }
- $this->iterator = new ArrayIterator($array);
- } elseif ($source instanceof Iterator) {
- $this->iterator = $source;
- } elseif ($source instanceof Traversable) {
- $this->iterator = new IteratorIterator($source);
- } elseif ($source instanceof stdClass) {
- $this->iterator = new ArrayIterator( (array) $source );
- } else {
- $this->iterator = new ArrayIterator( array() );
- }
- }
- /**
- * Returns the current element value in the iteration
- *
- * @return Mixed The current element value
- */
- public function current()
- {
- return $this->current;
- }
- /**
- * Returns the current element key in the iteration
- *
- * @return String/Int The current element key
- */
- public function key()
- {
- return $this->key;
- }
- /**
- * Tells if the iteration is over
- *
- * @return bool True if the iteration is not finished yet
- */
- public function valid()
- {
- $valid = $this->valid || $this->validOnNext;
- $this->validOnNext = $this->valid;
- return $valid;
- }
- public function length()
- {
- if ($this->length === null) {
- if ($this->iterator instanceof Countable) {
- return $this->length = count($this->iterator);
- } elseif ( is_object($this->iterator) ) {
- // for backwards compatibility with existing PHPTAL templates
- if ( method_exists($this->iterator, 'size') ) {
- return $this->length = $this->iterator->size();
- } elseif ( method_exists($this->iterator, 'length') ) {
- return $this->length = $this->iterator->length();
- }
- }
- $this->length = '_PHPTAL_LENGTH_UNKNOWN_';
- }
- if ($this->length === '_PHPTAL_LENGTH_UNKNOWN_') // return length if end is discovered
- {
- return $this->end ? $this->index + 1 : null;
- }
- return $this->length;
- }
- /**
- * Restarts the iteration process going back to the first element
- *
- */
- public function rewind()
- {
- $this->index = 0;
- $this->length = null;
- $this->end = false;
- $this->iterator->rewind();
- // Prefetch the next element
- if ($this->iterator->valid()) {
- $this->validOnNext = true;
- $this->prefetch();
- } else {
- $this->validOnNext = false;
- }
- if ($this->uses_groups) {
- // Notify the grouping helper of the change
- $this->groups->reset();
- }
- }
- /**
- * Fetches the next element in the iteration and advances the pointer
- *
- */
- public function next()
- {
- $this->index++;
- // Prefetch the next element
- if ($this->validOnNext) $this->prefetch();
- if ($this->uses_groups) {
- // Notify the grouping helper of the change
- $this->groups->reset();
- }
- }
- /**
- * Ensures that $this->groups works.
- *
- * Groups are rarely-used feature, which is why they're lazily loaded.
- */
- private function initializeGroups()
- {
- if (!$this->uses_groups) {
- $this->groups = new PHPTAL_RepeatControllerGroups();
- $this->uses_groups = true;
- }
- }
- /**
- * Gets an object property
- *
- * @return $var Mixed The variable value
- */
- public function __get($var)
- {
- switch ($var) {
- case 'number':
- return $this->index + 1;
- case 'start':
- return $this->index === 0;
- case 'even':
- return ($this->index % 2) === 0;
- case 'odd':
- return ($this->index % 2) === 1;
- case 'length':
- return $this->length();
- case 'letter':
- return strtolower( $this->int2letter($this->index+1) );
- case 'Letter':
- return strtoupper( $this->int2letter($this->index+1) );
- case 'roman':
- return strtolower( $this->int2roman($this->index+1) );
- case 'Roman':
- return strtoupper( $this->int2roman($this->index+1) );
- case 'groups':
- $this->initializeGroups();
- return $this->groups;
- case 'first':
- $this->initializeGroups();
- // Compare the current one with the previous in the dictionary
- $res = $this->groups->first($this->current);
- return is_bool($res) ? $res : $this->groups;
- case 'last':
- $this->initializeGroups();
- // Compare the next one with the dictionary
- $res = $this->groups->last( $this->iterator->current() );
- return is_bool($res) ? $res : $this->groups;
- default:
- throw new PHPTAL_VariableNotFoundException("Unable to find part '$var' in repeat variable");
- }
- }
- /**
- * Fetches the next element from the source data store and
- * updates the end flag if needed.
- *
- * @access protected
- */
- protected function prefetch()
- {
- $this->valid = true;
- $this->current = $this->iterator->current();
- $this->key = $this->iterator->key();
- $this->iterator->next();
- if ( !$this->iterator->valid() ) {
- $this->valid = false;
- $this->end = true;
- }
- }
- /**
- * Converts an integer number (1 based) to a sequence of letters
- *
- * @param int $int The number to convert
- *
- * @return String The letters equivalent as a, b, c-z ... aa, ab, ac-zz ...
- * @access protected
- */
- protected function int2letter($int)
- {
- $lookup = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
- $size = strlen($lookup);
- $letters = '';
- while ($int > 0) {
- $int--;
- $letters = $lookup[$int % $size] . $letters;
- $int = floor($int / $size);
- }
- return $letters;
- }
- /**
- * Converts an integer number (1 based) to a roman numeral
- *
- * @param int $int The number to convert
- *
- * @return String The roman numeral
- * @access protected
- */
- protected function int2roman($int)
- {
- $lookup = array(
- '1000' => 'M',
- '900' => 'CM',
- '500' => 'D',
- '400' => 'CD',
- '100' => 'C',
- '90' => 'XC',
- '50' => 'L',
- '40' => 'XL',
- '10' => 'X',
- '9' => 'IX',
- '5' => 'V',
- '4' => 'IV',
- '1' => 'I',
- );
- $roman = '';
- foreach ($lookup as $max => $letters) {
- while ($int >= $max) {
- $roman .= $letters;
- $int -= $max;
- }
- }
- return $roman;
- }
- }