|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
|
|
namespace App\Tables;
|
|
|
|
|
|
|
|
|
|
|
|
use App\Models\Row;
|
|
|
|
use App\Models\Table;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Table exporter base class
|
|
|
|
*/
|
|
|
|
abstract class BaseExporter
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* @var Table the table to export
|
|
|
|
*/
|
|
|
|
protected $table;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @var Column[] - parsed columns for the table
|
|
|
|
*/
|
|
|
|
protected $columns;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @var bool - true if user wants download; can e.g. change mime type to text/plain if not
|
|
|
|
*/
|
|
|
|
protected $wantDownload;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* TODO export options from enabled columns, sorts, etc
|
|
|
|
*
|
|
|
|
* @param Table $table
|
|
|
|
*/
|
|
|
|
public function __construct(Table $table)
|
|
|
|
{
|
|
|
|
$this->table = $table;
|
|
|
|
$this->columns = Column::columnsFromJson($table->revision->columns);
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function getHeaderComment($prefix = " ")
|
|
|
|
{
|
|
|
|
$table = $this->table;
|
|
|
|
$owner = $this->table->owner;
|
|
|
|
|
|
|
|
$s =
|
|
|
|
$prefix."Table \"$table->title\" by $owner->title\n".
|
|
|
|
$prefix."exported ".date('M n, Y \\a\\t G:i')."\n".
|
|
|
|
$prefix."\n".
|
|
|
|
$prefix."License: ". str_replace("\n", "\n$prefix", $table->license ?: 'CC0') ."\n".
|
|
|
|
$prefix."\n".
|
|
|
|
$prefix."Upstream: https://datatable.directory/$owner->handle/$table->name\n";
|
|
|
|
|
|
|
|
$s .=
|
|
|
|
$prefix."\n".
|
|
|
|
$prefix."Columns:\n";
|
|
|
|
|
|
|
|
foreach ($this->columns as $c) {
|
|
|
|
$s .= $prefix." - $c->name ... $c->title\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
return $s;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return string - mime type for the downloaded file
|
|
|
|
*/
|
|
|
|
protected abstract function getMimeType();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return string - file extension for the downloaded file
|
|
|
|
*/
|
|
|
|
protected abstract function getFileExtension();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return string - file name without extension, by default the table name
|
|
|
|
*/
|
|
|
|
protected function getFileBasename()
|
|
|
|
{
|
|
|
|
return $this->table->name;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Generate a response that appears as a file download to the browser
|
|
|
|
*
|
|
|
|
* @param bool $download - force download, otherwise the browser may show it in the window
|
|
|
|
*/
|
|
|
|
public function exportToBrowser($download = true)
|
|
|
|
{
|
|
|
|
$this->wantDownload = $download;
|
|
|
|
|
|
|
|
$mimeType = $this->getMimeType();
|
|
|
|
$filename = $this->getFileBasename() . '.' . $this->getFileExtension();
|
|
|
|
|
|
|
|
ob_end_clean();
|
|
|
|
|
|
|
|
// Redirect output to a client’s web browser
|
|
|
|
header("Content-Type: $mimeType; charset=utf-8");
|
|
|
|
|
|
|
|
if ($download) {
|
|
|
|
header("Content-Disposition: attachment;filename=\"$filename\"");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Cache headers
|
|
|
|
header('Cache-Control: max-age=0');
|
|
|
|
// IE9
|
|
|
|
header('Cache-Control: max-age=1');
|
|
|
|
// Other IE headers
|
|
|
|
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); // Date in the past
|
|
|
|
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT'); // always modified
|
|
|
|
header('Cache-Control: cache, must-revalidate'); // HTTP/1.1
|
|
|
|
header('Pragma: no-cache'); // HTTP/1.0
|
|
|
|
|
|
|
|
$this->writeDocument();
|
|
|
|
exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Generator that produces PHP arrays for all rows, fetched from the DB in given chunks.
|
|
|
|
*
|
|
|
|
* @param int $chunkSize - size of one chunk
|
|
|
|
* @return \Generator|array[]
|
|
|
|
*/
|
|
|
|
protected function iterateRows($chunkSize = 1000)
|
|
|
|
{
|
|
|
|
$revision = $this->table->revision;
|
|
|
|
|
|
|
|
$count = $revision->rows()->count();
|
|
|
|
|
|
|
|
$start = 0;
|
|
|
|
|
|
|
|
$rq = $revision->rowsData($this->columns, false);
|
|
|
|
|
|
|
|
$columns = $this->columns;
|
|
|
|
|
|
|
|
// TODO raw query to allow selecting aggregates, column subsets, etc
|
|
|
|
if (count($columns)) $rq = $rq->sortByCol($columns[0]);
|
|
|
|
|
|
|
|
Row::disableCasts();
|
|
|
|
while ($start < $count) {
|
|
|
|
$rows = $rq->offset($start)->limit($chunkSize)->get()->toArray();
|
|
|
|
|
|
|
|
foreach ($rows as $row) {
|
|
|
|
unset($row['_row_pivot']);
|
|
|
|
yield $row;
|
|
|
|
}
|
|
|
|
|
|
|
|
$start += $chunkSize;
|
|
|
|
}
|
|
|
|
Row::enableCasts();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Write the document to stdout ('php://output')
|
|
|
|
*/
|
|
|
|
protected abstract function writeDocument();
|
|
|
|
}
|