Polyfill
10 months ago
AbstractCsv.php
10 months ago
ByteSequence.php
10 months ago
CannotInsertRecord.php
10 months ago
CharsetConverter.php
10 months ago
ColumnConsistency.php
10 months ago
EncloseField.php
10 months ago
EscapeFormula.php
10 months ago
Exception.php
10 months ago
HTMLConverter.php
10 months ago
Info.php
10 months ago
InvalidArgument.php
10 months ago
MapIterator.php
10 months ago
RFC4180Field.php
10 months ago
Reader.php
10 months ago
ResultSet.php
10 months ago
Statement.php
10 months ago
Stream.php
10 months ago
SyntaxError.php
10 months ago
TabularDataReader.php
10 months ago
UnableToProcessCsv.php
10 months ago
UnavailableFeature.php
10 months ago
UnavailableStream.php
10 months ago
Writer.php
10 months ago
XMLConverter.php
10 months ago
functions.php
10 months ago
functions_include.php
10 months ago
Statement.php
160 lines
| 1 | <?php |
| 2 | |
| 3 | /** |
| 4 | * League.Csv (https://csv.thephpleague.com) |
| 5 | * |
| 6 | * (c) Ignace Nyamagana Butera <nyamsprod@gmail.com> |
| 7 | * |
| 8 | * For the full copyright and license information, please view the LICENSE |
| 9 | * file that was distributed with this source code. |
| 10 | */ |
| 11 | declare (strict_types=1); |
| 12 | namespace IAWPSCOPED\League\Csv; |
| 13 | |
| 14 | use ArrayIterator; |
| 15 | use CallbackFilterIterator; |
| 16 | use Iterator; |
| 17 | use LimitIterator; |
| 18 | use function array_reduce; |
| 19 | /** |
| 20 | * Criteria to filter a {@link Reader} object. |
| 21 | * @internal |
| 22 | */ |
| 23 | class Statement |
| 24 | { |
| 25 | /** |
| 26 | * Callables to filter the iterator. |
| 27 | * |
| 28 | * @var array<callable> |
| 29 | */ |
| 30 | protected $where = []; |
| 31 | /** |
| 32 | * Callables to sort the iterator. |
| 33 | * |
| 34 | * @var array<callable> |
| 35 | */ |
| 36 | protected $order_by = []; |
| 37 | /** |
| 38 | * iterator Offset. |
| 39 | * |
| 40 | * @var int |
| 41 | */ |
| 42 | protected $offset = 0; |
| 43 | /** |
| 44 | * iterator maximum length. |
| 45 | * |
| 46 | * @var int |
| 47 | */ |
| 48 | protected $limit = -1; |
| 49 | /** |
| 50 | * Named Constructor to ease Statement instantiation. |
| 51 | * |
| 52 | * @throws Exception |
| 53 | */ |
| 54 | public static function create(callable $where = null, int $offset = 0, int $limit = -1) : self |
| 55 | { |
| 56 | $stmt = new self(); |
| 57 | if (null !== $where) { |
| 58 | $stmt = $stmt->where($where); |
| 59 | } |
| 60 | return $stmt->offset($offset)->limit($limit); |
| 61 | } |
| 62 | /** |
| 63 | * Set the Iterator filter method. |
| 64 | */ |
| 65 | public function where(callable $where) : self |
| 66 | { |
| 67 | $clone = clone $this; |
| 68 | $clone->where[] = $where; |
| 69 | return $clone; |
| 70 | } |
| 71 | /** |
| 72 | * Set an Iterator sorting callable function. |
| 73 | */ |
| 74 | public function orderBy(callable $order_by) : self |
| 75 | { |
| 76 | $clone = clone $this; |
| 77 | $clone->order_by[] = $order_by; |
| 78 | return $clone; |
| 79 | } |
| 80 | /** |
| 81 | * Set LimitIterator Offset. |
| 82 | * |
| 83 | * @throws Exception if the offset is lesser than 0 |
| 84 | */ |
| 85 | public function offset(int $offset) : self |
| 86 | { |
| 87 | if (0 > $offset) { |
| 88 | throw InvalidArgument::dueToInvalidRecordOffset($offset, __METHOD__); |
| 89 | } |
| 90 | if ($offset === $this->offset) { |
| 91 | return $this; |
| 92 | } |
| 93 | $clone = clone $this; |
| 94 | $clone->offset = $offset; |
| 95 | return $clone; |
| 96 | } |
| 97 | /** |
| 98 | * Set LimitIterator Count. |
| 99 | * |
| 100 | * @throws Exception if the limit is lesser than -1 |
| 101 | */ |
| 102 | public function limit(int $limit) : self |
| 103 | { |
| 104 | if (-1 > $limit) { |
| 105 | throw InvalidArgument::dueToInvalidLimit($limit, __METHOD__); |
| 106 | } |
| 107 | if ($limit === $this->limit) { |
| 108 | return $this; |
| 109 | } |
| 110 | $clone = clone $this; |
| 111 | $clone->limit = $limit; |
| 112 | return $clone; |
| 113 | } |
| 114 | /** |
| 115 | * Execute the prepared Statement on the {@link Reader} object. |
| 116 | * |
| 117 | * @param array<string> $header an optional header to use instead of the CSV document header |
| 118 | */ |
| 119 | public function process(TabularDataReader $tabular_data, array $header = []) : TabularDataReader |
| 120 | { |
| 121 | if ([] === $header) { |
| 122 | $header = $tabular_data->getHeader(); |
| 123 | } |
| 124 | $iterator = $tabular_data->getRecords($header); |
| 125 | $iterator = array_reduce($this->where, [$this, 'filter'], $iterator); |
| 126 | $iterator = $this->buildOrderBy($iterator); |
| 127 | return new ResultSet(new LimitIterator($iterator, $this->offset, $this->limit), $header); |
| 128 | } |
| 129 | /** |
| 130 | * Filters elements of an Iterator using a callback function. |
| 131 | */ |
| 132 | protected function filter(Iterator $iterator, callable $callable) : CallbackFilterIterator |
| 133 | { |
| 134 | return new CallbackFilterIterator($iterator, $callable); |
| 135 | } |
| 136 | /** |
| 137 | * Sort the Iterator. |
| 138 | */ |
| 139 | protected function buildOrderBy(Iterator $iterator) : Iterator |
| 140 | { |
| 141 | if ([] === $this->order_by) { |
| 142 | return $iterator; |
| 143 | } |
| 144 | $compare = function (array $record_a, array $record_b) : int { |
| 145 | foreach ($this->order_by as $callable) { |
| 146 | if (0 !== ($cmp = $callable($record_a, $record_b))) { |
| 147 | return $cmp; |
| 148 | } |
| 149 | } |
| 150 | return $cmp ?? 0; |
| 151 | }; |
| 152 | $it = new ArrayIterator(); |
| 153 | foreach ($iterator as $offset => $value) { |
| 154 | $it[$offset] = $value; |
| 155 | } |
| 156 | $it->uasort($compare); |
| 157 | return $it; |
| 158 | } |
| 159 | } |
| 160 |