Skip to content

Commit 72e0736

Browse files
authored
Merge pull request #106 from luads/options_columns
Options columns
2 parents 7c6a328 + 1614f24 commit 72e0736

File tree

10 files changed

+136
-30
lines changed

10 files changed

+136
-30
lines changed

example/test-columns.php

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
<?php
2+
3+
use XBase\Enum\FieldType;
4+
use XBase\Enum\TableType;
5+
use XBase\Header\Column;
6+
use XBase\Header\HeaderFactory;
7+
use XBase\TableCreator;
8+
use XBase\TableEditor;
9+
use XBase\TableReader;
10+
11+
require_once '../vendor/autoload.php';
12+
13+
$columnsCount = 30;
14+
15+
$filepath = __DIR__.'/db.dbf';
16+
if (file_exists($filepath)) {
17+
unlink($filepath);
18+
}
19+
20+
createFile($filepath, $columnsCount);
21+
generateData($filepath, $columnsCount);
22+
collectPerformanceInfo($filepath);
23+
collectPerformanceInfo($filepath, 100, ['name_4', 'bio_10', 'is_man_8']);
24+
25+
function createFile(string $filepath, int $columnsCount): void
26+
{
27+
$header = HeaderFactory::create(TableType::DBASE_III_PLUS_MEMO);
28+
29+
$tableCreator = new TableCreator($filepath, $header);
30+
31+
for ($i = 0; $i <= $columnsCount; $i++) {
32+
$tableCreator
33+
->addColumn(new Column([
34+
'name' => "name_$i",
35+
'type' => FieldType::CHAR,
36+
'length' => 20,
37+
]))
38+
->addColumn(new Column([
39+
'name' => "birthday_$i",
40+
'type' => FieldType::DATE,
41+
]))
42+
->addColumn(new Column([
43+
'name' => "is_man_$i",
44+
'type' => FieldType::LOGICAL,
45+
]))
46+
->addColumn(new Column([
47+
'name' => "bio_$i",
48+
'type' => FieldType::MEMO,
49+
]))
50+
->addColumn(new Column([
51+
'name' => "money_$i",
52+
'type' => FieldType::NUMERIC,
53+
'length' => 20,
54+
'decimalCount' => 4,
55+
]));
56+
}
57+
58+
$tableCreator->save();
59+
}
60+
61+
function generateData(string $filepath, int $columnsCount): void
62+
{
63+
$table = new TableEditor($filepath);
64+
65+
$date = new \DateTimeImmutable('1970-01-01');
66+
67+
for ($i = 0; $i < $columnsCount; $i++) {
68+
$birthday = $date->add(new \DateInterval('P1D'));
69+
$record = $table->appendRecord()
70+
->set("name_$i", "column_$i")
71+
->set("birthday_$i", $birthday)
72+
->set("is_man_$i", $i % 2 === 0)
73+
->set("bio_$i", str_pad('', $i, '-'))
74+
->set("money_$i", rand(0, $i) * 0.1);
75+
$table->writeRecord($record);
76+
}
77+
78+
$table
79+
->save()
80+
->close();
81+
}
82+
83+
function collectPerformanceInfo(string $filepath, int $iterations = 100, array $columns = [])
84+
{
85+
$timetable = [];
86+
87+
printf('Reading all data'.PHP_EOL);
88+
89+
for ($i = 0; $i < $iterations; $i++) {
90+
$startTime = microtime(true);
91+
$tableReader = new TableReader($filepath, ['columns' => $columns]);
92+
93+
while ($record = $tableReader->nextRecord()) {
94+
foreach ($tableReader->getColumns() as $column) {
95+
try {
96+
$value = $record->get($column->getName());
97+
} catch (\Throwable $exc) {
98+
}
99+
}
100+
}
101+
102+
$tableReader->close();
103+
104+
$timetable[] = microtime(true) - $startTime;
105+
106+
printf('.');
107+
}
108+
109+
printf(PHP_EOL);
110+
$avg = $average = array_sum($timetable) / count($timetable);
111+
printf('AVG time to read all tables data: %f%s', $avg, PHP_EOL);
112+
}

src/Header/Reader/AbstractHeaderReader.php

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,18 @@ abstract class AbstractHeaderReader implements HeaderReaderInterface
1919
/** @var Header|null */
2020
protected $header;
2121

22-
public function __construct(string $filepath)
22+
/** @var array */
23+
protected $options;
24+
25+
/**
26+
* @param array $options Array of options:<br>
27+
* columns - available columns<br>
28+
*/
29+
public function __construct(string $filepath, array $options = [])
2330
{
2431
$this->filepath = $filepath;
2532
$this->fp = Stream::createFromFile($filepath);
33+
$this->options = $options;
2634
}
2735

2836
public function read(): Header
@@ -57,14 +65,18 @@ protected function readColumns(): void
5765
throw new TableException(sprintf('File %s is not DBF', $this->filepath));
5866
}
5967

68+
$targetColumns = $this->options['columns'] ?? [];
69+
6070
$bytePos = 1;
6171
$columnReader = ColumnReaderFactory::create($this->header->version);
6272
for ($i = 0; $i < $columnsCount; $i++) {
6373
$column = $columnReader->read($this->fp);
64-
$column->columnIndex = $i;
65-
$column->bytePosition = $bytePos;
74+
if (empty($targetColumns) || in_array($column->name, $targetColumns)) {
75+
$column->columnIndex = $i;
76+
$column->bytePosition = $bytePos;
6677

67-
$this->header->columns[] = $column;
78+
$this->header->columns[] = $column;
79+
}
6880

6981
$bytePos += $column->length;
7082
}

src/Header/Reader/HeaderReaderFactory.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,22 +12,22 @@
1212
*/
1313
class HeaderReaderFactory
1414
{
15-
public static function create(string $filepath): HeaderReaderInterface
15+
public static function create(string $filepath, array $options = []): HeaderReaderInterface
1616
{
1717
$stream = Stream::createFromFile($filepath);
1818
$version = $stream->readUChar();
1919
$stream->close();
2020

2121
if (TableType::isVisualFoxpro($version)) {
22-
return new VisualFoxproHeaderReader($filepath);
22+
return new VisualFoxproHeaderReader($filepath, $options);
2323
}
2424

2525
switch ($version) {
2626
case TableType::DBASE_7_MEMO:
2727
case TableType::DBASE_7_NOMEMO:
28-
return new DBase7HeaderReader($filepath);
28+
return new DBase7HeaderReader($filepath, $options);
2929
default:
30-
return new DBaseHeaderReader($filepath);
30+
return new DBaseHeaderReader($filepath, $options);
3131
}
3232
}
3333
}

src/Memo/AbstractMemo.php

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,6 @@ public static function getExtension(): string
4747
return 'dbt';
4848
}
4949

50-
/**
51-
* {@inheritdoc}
52-
*/
5350
public function isOpen(): bool
5451
{
5552
return null !== $this->fp;

src/Memo/Creator/MemoCreatorFactory.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ public static function create(Table $table)
1818
return new DBase4MemoCreator($table);
1919
case TableType::DBASE_7_MEMO:
2020
return new DBase7MemoCreator($table);
21-
//todo voxpro
21+
//todo foxpro
2222
default:
2323
throw new \Exception('Memo creator not realized for table version '.$table->getVersion());
2424
}

src/Record/AbstractRecord.php

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,6 @@ abstract class AbstractRecord implements RecordInterface
1717
protected $table;
1818
/** @var array */
1919
protected $data;
20-
/**
21-
* @var array
22-
*
23-
* @deprecated
24-
*/
25-
protected $choppedData = [];
2620
/** @var bool */
2721
protected $deleted = false;
2822
/** @var int */
@@ -34,13 +28,11 @@ public function __construct(Table $table, int $recordIndex, array $data = [])
3428
$this->recordIndex = $recordIndex;
3529
$this->data = $data['data'] ?? [];
3630
$this->deleted = $data['deleted'] ?? false;
37-
$this->choppedData = $data['choppedData'] ?? [];
3831
}
3932

4033
public function destroy(): void
4134
{
4235
$this->table = null;
43-
$this->choppedData = null;
4436
}
4537

4638
public function __get(string $name)

src/Record/RecordFactory.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
use XBase\DataConverter\Record\DBase7DataConverter;
77
use XBase\DataConverter\Record\DBaseDataConverter;
88
use XBase\DataConverter\Record\FoxproDataConverter;
9-
use XBase\DataConverter\Record\HasFieldConvertersInterface;
109
use XBase\DataConverter\Record\RecordDataConverterInterface;
1110
use XBase\DataConverter\Record\VisualFoxproDataConverter;
1211
use XBase\Enum\TableType;
@@ -55,7 +54,7 @@ public static function getClass(int $version): string
5554
}
5655

5756
/**
58-
* @return RecordDataConverterInterface|HasFieldConvertersInterface
57+
* @return RecordDataConverterInterface
5958
*/
6059
public static function createDataConverter(Table $table): RecordDataConverterInterface
6160
{

src/TableReader.php

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ protected function open(): void
8686

8787
protected function readHeader(): void
8888
{
89-
$this->table->header = HeaderReaderFactory::create($this->getFilepath())->read();
89+
$this->table->header = HeaderReaderFactory::create($this->getFilepath(), $this->table->options)->read();
9090
$this->getStream()->seek($this->table->header->length);
9191

9292
$this->recordPos = -1;
@@ -226,11 +226,9 @@ public function moveTo(int $index): ?RecordInterface
226226
}
227227

228228
/**
229-
* @param string $name
230-
*
231229
* @return ColumnInterface
232230
*/
233-
public function getColumn($name)
231+
public function getColumn(string $name)
234232
{
235233
foreach ($this->getHeader()->columns as $column) {
236234
if ($column->name === $name) {

tests/TableReader/FoxproTest.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@ public function testFoxpro2(): void
6363
self::assertSame(TableType::FOXPRO_MEMO, $table->getVersion());
6464
self::assertSame(Codepage::CP1252, $table->getCodepage());
6565
self::assertSame(true, $table->isFoxpro());
66-
self::assertSame(true, $table->isFoxpro());
6766
self::assertSame(289, $table->getHeaderLength());
6867
self::assertSame(90, $table->getRecordByteLength());
6968
self::assertSame(false, $table->isInTransaction());

tests/TableReaderTest.php

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ public function testRead(): void
2525
self::assertSame(TableType::DBASE_III_PLUS_NOMEMO, $table->getVersion());
2626
self::assertSame(Codepage::UNDEFINED, $table->getCodepage());
2727
self::assertSame(false, $table->isFoxpro());
28-
self::assertSame(false, $table->isFoxpro());
2928
self::assertSame(1580774400, $table->getModifyDate());
3029
self::assertSame(609, $table->getHeaderLength());
3130
self::assertSame(225, $table->getRecordByteLength());
@@ -151,7 +150,6 @@ public function testDbase3(): void
151150

152151
self::assertSame(TableType::DBASE_III_PLUS_MEMO, $table->getVersion());
153152
self::assertSame(Codepage::CP1252, $table->getCodepage());
154-
self::assertSame(false, $table->isFoxpro()); //todo why true
155153
self::assertSame(false, $table->isFoxpro());
156154
self::assertSame(225, $table->getHeaderLength());
157155
self::assertSame(70, $table->getRecordByteLength());
@@ -203,7 +201,6 @@ public function testDbase4(): void
203201
self::assertSame(TableType::DBASE_IV_MEMO, $table->getVersion());
204202
self::assertSame(Codepage::CP1252, $table->getCodepage());
205203
self::assertSame(false, $table->isFoxpro());
206-
self::assertSame(false, $table->isFoxpro());
207204
self::assertSame(257, $table->getHeaderLength());
208205
self::assertSame(80, $table->getRecordByteLength());
209206
self::assertSame(false, $table->isInTransaction());

0 commit comments

Comments
 (0)