Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 84 additions & 0 deletions examples/incremental-table.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
<?php

require_once 'common.php';

/**
* Example demonstrating the incremental table row display feature.
* This shows how to display a table header once and then add rows incrementally in a loop.
*/

echo "Example 1: Using displayRow() to add rows incrementally\n";
echo "=========================================================\n\n";

$table = new \cli\Table();
$table->setHeaders(array('File Name', 'Status', 'Progress'));
$table->display();

// Simulate processing items in a loop
$items = array(
array('file1.txt', 'Done', '100%'),
array('file2.txt', 'Done', '100%'),
array('file3.txt', 'Done', '100%'),
array('file4.txt', 'Done', '100%'),
);

foreach ($items as $item) {
// Add some delay to simulate processing
usleep(200000); // 0.2 seconds
$table->displayRow($item);
}

echo "\n\nExample 2: Using resetRows() with incremental display\n";
echo "========================================================\n\n";

$table2 = new \cli\Table();
$table2->setHeaders(array('Name', 'Age', 'City'));
$table2->display();

echo "Adding first batch of rows...\n";
$table2->displayRow(array('Alice', '30', 'New York'));
$table2->displayRow(array('Bob', '25', 'London'));

echo "\nClearing rows and adding new batch...\n";
$table2->resetRows();
$table2->displayRow(array('Charlie', '35', 'Paris'));
$table2->displayRow(array('Diana', '28', 'Tokyo'));

echo "\n\nExample 3: Real-time progress display\n";
echo "========================================\n\n";

$table3 = new \cli\Table();
$table3->setHeaders(array('Task', 'Result'));
$table3->display();

$tasks = array(
array('Initialize database', 'OK'),
array('Load configuration', 'OK'),
array('Connect to API', 'OK'),
array('Process data', 'OK'),
array('Generate report', 'OK'),
);

foreach ($tasks as $task) {
usleep(300000); // 0.3 seconds
$table3->displayRow($task);
}

echo "\n\nExample 4: Tabular format (for piped output)\n";
echo "==============================================\n\n";

$table4 = new \cli\Table();
$table4->setRenderer(new \cli\table\Tabular());
$table4->setHeaders(array('ID', 'Name', 'Email'));
$table4->display();

$users = array(
array('1', 'John Doe', 'john@example.com'),
array('2', 'Jane Smith', 'jane@example.com'),
array('3', 'Bob Johnson', 'bob@example.com'),
);

foreach ($users as $user) {
usleep(100000); // 0.1 seconds
$table4->displayRow($user);
}
44 changes: 43 additions & 1 deletion lib/cli/Table.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ class Table {
protected $_footers = array();
protected $_width = array();
protected $_rows = array();
protected $_displayed = false;

/**
* Initializes the `Table` class.
Expand Down Expand Up @@ -79,6 +80,18 @@ public function resetTable()
$this->_width = array();
$this->_rows = array();
$this->_footers = array();
$this->_displayed = false;
return $this;
}

/**
* Resets only the rows in the table, keeping headers, footers, and width information.
*
* @return $this
*/
public function resetRows()
{
$this->_rows = array();
return $this;
}

Expand Down Expand Up @@ -125,6 +138,34 @@ public function display() {
foreach( $this->getDisplayLines() as $line ) {
Streams::line( $line );
}
$this->_displayed = true;
}

/**
* Display a single row without headers or top border.
*
* This method is useful for adding rows incrementally to an already-rendered table.
* It will display the row with side borders and a bottom border (if using Ascii renderer).
*
* @param array $row The row data to display.
*/
public function displayRow(array $row) {
// Update widths if this row has wider content
$row = $this->checkRow($row);

// Recalculate widths for the renderer
$this->_renderer->setWidths($this->_width, $fallback = false);

$rendered_row = $this->_renderer->row($row);
$row_lines = explode( PHP_EOL, $rendered_row );
foreach ( $row_lines as $line ) {
Streams::line( $line );
}

$border = $this->_renderer->border();
if (isset($border)) {
Streams::line( $border );
}
}

/**
Expand Down Expand Up @@ -154,7 +195,8 @@ public function getDisplayLines() {
$out = array_merge( $out, $row );
}

if (isset($border)) {
// Only add final border if there are rows
if (!empty($this->_rows) && isset($border)) {
$out[] = $border;
}

Expand Down
2 changes: 2 additions & 0 deletions lib/cli/table/Ascii.php
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ public function setWidths(array $widths, $fallback = false) {
}

$this->_widths = $widths;
// Reset border cache when widths change
$this->_border = null;
}

/**
Expand Down
63 changes: 63 additions & 0 deletions tests/Test_Table.php
Original file line number Diff line number Diff line change
Expand Up @@ -289,4 +289,67 @@ public function test_null_values_are_handled() {
];
$this->assertSame( $expected, $out, 'Null values should be safely converted to empty strings in table output.' );
}

public function test_resetRows() {
$table = new cli\Table();
$table->setHeaders( array( 'Name', 'Age' ) );
$table->addRow( array( 'Alice', '30' ) );
$table->addRow( array( 'Bob', '25' ) );

$this->assertEquals( 2, $table->countRows() );

$table->resetRows();

$this->assertEquals( 0, $table->countRows() );

// Headers should still be intact
$out = $table->getDisplayLines();
$this->assertGreaterThan( 0, count( $out ) );
}

public function test_displayRow_ascii() {
$mockFile = tempnam(sys_get_temp_dir(), 'temp');
$resource = fopen($mockFile, 'wb');
\cli\Streams::setStream('out', $resource);

$table = new cli\Table();
$renderer = new cli\Table\Ascii();
$table->setRenderer( $renderer );
$table->setHeaders( array( 'Name', 'Age' ) );

// Display a single row
$table->displayRow( array( 'Alice', '30' ) );

$output = file_get_contents($mockFile);
unlink($mockFile);

// Should contain the row data
$this->assertStringContainsString( 'Alice', $output );
$this->assertStringContainsString( '30', $output );

// Should contain borders
$this->assertStringContainsString( '|', $output );
$this->assertStringContainsString( '+', $output );
}

public function test_displayRow_tabular() {
$mockFile = tempnam(sys_get_temp_dir(), 'temp');
$resource = fopen($mockFile, 'wb');
\cli\Streams::setStream('out', $resource);

$table = new cli\Table();
$renderer = new cli\Table\Tabular();
$table->setRenderer( $renderer );
$table->setHeaders( array( 'Name', 'Age' ) );

// Display a single row
$table->displayRow( array( 'Alice', '30' ) );

$output = file_get_contents($mockFile);
unlink($mockFile);

// Should contain the row data with tabs
$this->assertStringContainsString( 'Alice', $output );
$this->assertStringContainsString( '30', $output );
}
}
1 change: 0 additions & 1 deletion tests/Test_Table_Ascii.php
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,6 @@ public function testDrawWithHeadersNoData() {
+----------+----------+
| header 1 | header 2 |
+----------+----------+
+----------+----------+

OUT;
$this->assertInOutEquals(array($headers, $rows), $output);
Expand Down