4 * This file is part of the Behat Gherkin.
5 * (c) Konstantin Kudryashov <ever.zet@gmail.com>
7 * For the full copyright and license information, please view the LICENSE
8 * file that was distributed with this source code.
11 namespace Behat\Gherkin\Node;
14 use Behat\Gherkin\Exception\NodeException;
16 use IteratorAggregate;
19 * Represents Gherkin Table argument.
21 * @author Konstantin Kudryashov <ever.zet@gmail.com>
23 class TableNode implements ArgumentInterface, IteratorAggregate
32 private $maxLineLength = array();
37 * @param array $table Table in form of [$rowLineNumber => [$val1, $val2, $val3]]
39 * @throws NodeException If the given table is invalid
41 public function __construct(array $table)
43 $this->table = $table;
46 foreach ($this->getRows() as $row) {
47 if ($columnCount === null) {
48 $columnCount = count($row);
51 if (count($row) !== $columnCount) {
52 throw new NodeException('Table does not have same number of columns in every row.');
55 if (!is_array($row)) {
56 throw new NodeException('Table is not two-dimensional.');
59 foreach ($row as $column => $string) {
60 if (!isset($this->maxLineLength[$column])) {
61 $this->maxLineLength[$column] = 0;
64 if (!is_scalar($string)) {
65 throw new NodeException('Table is not two-dimensional.');
68 $this->maxLineLength[$column] = max($this->maxLineLength[$column], mb_strlen($string, 'utf8'));
74 * Creates a table from a given list.
76 * @param array $list One-dimensional array
80 * @throws NodeException If the given list is not a one-dimensional array
82 public static function fromList(array $list)
84 if (count($list) !== count($list, COUNT_RECURSIVE)) {
85 throw new NodeException('List is not a one-dimensional array.');
88 array_walk($list, function (&$item) {
91 return new self($list);
99 public function getNodeType()
105 * Returns table hash, formed by columns (ColumnsHash).
109 public function getHash()
111 return $this->getColumnsHash();
115 * Returns table hash, formed by columns.
119 public function getColumnsHash()
121 $rows = $this->getRows();
122 $keys = array_shift($rows);
125 foreach ($rows as $row) {
126 $hash[] = array_combine($keys, $row);
133 * Returns table hash, formed by rows.
137 public function getRowsHash()
141 foreach ($this->getRows() as $row) {
142 $hash[array_shift($row)] = (1 == count($row)) ? $row[0] : $row;
149 * Returns numerated table lines.
150 * Line numbers are keys, lines are values.
154 public function getTable()
160 * Returns table rows.
164 public function getRows()
166 return array_values($this->table);
170 * Returns table definition lines.
174 public function getLines()
176 return array_keys($this->table);
180 * Returns specific row in a table.
182 * @param integer $index Row number
186 * @throws NodeException If row with specified index does not exist
188 public function getRow($index)
190 $rows = $this->getRows();
192 if (!isset($rows[$index])) {
193 throw new NodeException(sprintf('Rows #%d does not exist in table.', $index));
196 return $rows[$index];
200 * Returns specific column in a table.
202 * @param integer $index Column number
206 * @throws NodeException If column with specified index does not exist
208 public function getColumn($index)
210 if ($index >= count($this->getRow(0))) {
211 throw new NodeException(sprintf('Column #%d does not exist in table.', $index));
214 $rows = $this->getRows();
217 foreach ($rows as $row) {
218 $column[] = $row[$index];
225 * Returns line number at which specific row was defined.
227 * @param integer $index
231 * @throws NodeException If row with specified index does not exist
233 public function getRowLine($index)
235 $lines = array_keys($this->table);
237 if (!isset($lines[$index])) {
238 throw new NodeException(sprintf('Rows #%d does not exist in table.', $index));
241 return $lines[$index];
245 * Converts row into delimited string.
247 * @param integer $rowNum Row number
251 public function getRowAsString($rowNum)
254 foreach ($this->getRow($rowNum) as $column => $value) {
255 $values[] = $this->padRight(' ' . $value . ' ', $this->maxLineLength[$column] + 2);
258 return sprintf('|%s|', implode('|', $values));
262 * Converts row into delimited string.
264 * @param integer $rowNum Row number
265 * @param callable $wrapper Wrapper function
269 public function getRowAsStringWithWrappedValues($rowNum, $wrapper)
272 foreach ($this->getRow($rowNum) as $column => $value) {
273 $value = $this->padRight(' ' . $value . ' ', $this->maxLineLength[$column] + 2);
275 $values[] = call_user_func($wrapper, $value, $column);
278 return sprintf('|%s|', implode('|', $values));
282 * Converts entire table into string
286 public function getTableAsString()
289 for ($i = 0; $i < count($this->getRows()); $i++) {
290 $lines[] = $this->getRowAsString($i);
293 return implode("\n", $lines);
297 * Returns line number at which table was started.
301 public function getLine()
303 return $this->getRowLine(0);
307 * Converts table into string
311 public function __toString()
313 return $this->getTableAsString();
317 * Retrieves a hash iterator.
321 public function getIterator()
323 return new ArrayIterator($this->getHash());
329 * @param string $text Text to pad
330 * @param integer $length Length
334 protected function padRight($text, $length)
336 while ($length > mb_strlen($text, 'utf8')) {