1 <?php
 2 
 3 /**
 4  * Sortable iterator.
 5  *
 6  * @author gharlan
 7  *
 8  * @package redaxo\core
 9  */
10 class rex_sortable_iterator implements IteratorAggregate
11 {
12     const VALUES = 1;
13     const KEYS = 2;
14 
15     private $iterator;
16     private $sort;
17 
18     /**
19      * Constructor.
20      *
21      * @param Traversable  $iterator Inner iterator
22      * @param int|callable $sort     Sort mode, possible values are rex_sortable_iterator::VALUES (default), rex_sortable_iterator::KEYS or a callable
23      */
24     public function __construct(Traversable $iterator, $sort = self::VALUES)
25     {
26         $this->iterator = $iterator;
27         $this->sort = $sort;
28     }
29 
30     /**
31      * {@inheritdoc}
32      */
33     public function getIterator()
34     {
35         $array = iterator_to_array($this->iterator);
36         $sort = is_callable($this->sort) ? 'callback' : $this->sort;
37         $normalize = function ($string) {
38             $string = preg_replace("/(?<=[aou])\xcc\x88/i", '', $string);
39             $string = mb_strtolower($string);
40             $string = str_replace(['ä', 'ö', 'ü', 'ß'], ['a', 'o', 'u', 's'], $string);
41             return $string;
42         };
43         $sortCallback = function ($a, $b) use ($normalize) {
44             $a = $normalize($a);
45             $b = $normalize($b);
46             return strnatcasecmp($a, $b);
47         };
48         switch ($sort) {
49             case self::VALUES:
50                 uasort($array, $sortCallback);
51                 break;
52             case self::KEYS:
53                 uksort($array, $sortCallback);
54                 break;
55             case 'callback':
56                 uasort($array, $this->sort);
57                 break;
58             default:
59                 throw new rex_exception('Unknown sort mode!');
60         }
61         return new ArrayIterator($array);
62     }
63 }
64