From 2267452d19f0acaf456222a9c5e499576dbdc68b Mon Sep 17 00:00:00 2001 From: gam6itko-job-pc Date: Thu, 10 Sep 2020 14:45:04 +0300 Subject: [PATCH] fix 89 --- .gitignore | 1 + src/XBase/Column/AbstractColumn.php | 10 ++ src/XBase/Column/ColumnFactory.php | 5 + src/XBase/Column/DBaseColumn.php | 65 ++++++++-- src/XBase/Column/VisualFoxproColumn.php | 19 +++ src/XBase/Memo/MemoFactory.php | 2 +- src/XBase/Record/AbstractRecord.php | 23 ++-- src/XBase/Record/VisualFoxproRecord.php | 86 +++++++++---- src/XBase/Table.php | 17 +-- src/XBase/WritableTable.php | 162 ++++++++---------------- tests/WritableTableTest.php | 158 +++++++++++++++++++++-- 11 files changed, 365 insertions(+), 183 deletions(-) create mode 100644 src/XBase/Column/VisualFoxproColumn.php diff --git a/.gitignore b/.gitignore index 5b66ed1..78ea60f 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ /vendor /.php_cs.cache /composer.lock +/.phpunit.result.cache diff --git a/src/XBase/Column/AbstractColumn.php b/src/XBase/Column/AbstractColumn.php index aafe7b9..c88fa9b 100644 --- a/src/XBase/Column/AbstractColumn.php +++ b/src/XBase/Column/AbstractColumn.php @@ -6,22 +6,32 @@ abstract class AbstractColumn implements ColumnInterface { /** @var string */ protected $name; + /** @var string */ protected $rawName; + /** @var string */ protected $type; + /** @var int */ protected $length; + /** @var int */ protected $decimalCount; /**@var int Field address within record. */ protected $memAddress; + protected $workAreaID; + + /** @var bool */ protected $setFields; + protected $indexed; + /** @var int|null Data starts from index */ protected $bytePos; + /** @var int */ protected $colIndex; diff --git a/src/XBase/Column/ColumnFactory.php b/src/XBase/Column/ColumnFactory.php index 2f7a5da..a9c5409 100644 --- a/src/XBase/Column/ColumnFactory.php +++ b/src/XBase/Column/ColumnFactory.php @@ -13,6 +13,11 @@ public static function getClass(string $version): string case TableType::DBASE_7_NOMEMO: return DBase7Column::class; + case TableType::VISUAL_FOXPRO: + case TableType::VISUAL_FOXPRO_AI: + case TableType::VISUAL_FOXPRO_VAR: + return VisualFoxproColumn::class; + default: return DBaseColumn::class; } diff --git a/src/XBase/Column/DBaseColumn.php b/src/XBase/Column/DBaseColumn.php index 8153e08..390d1c5 100644 --- a/src/XBase/Column/DBaseColumn.php +++ b/src/XBase/Column/DBaseColumn.php @@ -7,6 +7,12 @@ class DBaseColumn extends AbstractColumn { + protected $reserved1; + + protected $reserved2; + + protected $reserved3; + public static function getHeaderLength(): int { return 32; @@ -20,25 +26,38 @@ public static function create(string $memoryChunk, int $colIndex, ?int $bytePos $s = Stream::createFromString($memoryChunk); - return new self( - $s->read(11), - $s->read(), - $s->readUInt(), - $s->readUChar(), - $s->readUChar(), - $s->read(2), - $s->readUChar(), - $s->read(2), - 0 !== $s->read(), - $s->read(7), - 0 !== $s->read(), + return new static( + $s->read(11),//0-10 + $s->read(),//11 + $s->readUInt(),//12-15 + $s->readUChar(),//16 + $s->readUChar(),//17 + $s->read(2),//18-19 + $s->readUChar(),//20 + $s->read(2),//21-22 + 0 !== $s->readUChar(),//23 + $s->read(7),//24-30 + 0 !== $s->readUChar(),//31 $colIndex, $bytePos ); } - public function __construct(string $name, string $type, int $memAddress, int $length, int $decimalCount, $reserved1, int $workAreaID, $reserved2, bool $setFields, $reserved3, bool $indexed, int $colIndex, ?int $bytePos = null) - { + public function __construct( + string $name, + string $type, + int $memAddress, + int $length, + int $decimalCount, + $reserved1, + int $workAreaID, + $reserved2, + bool $setFields, + $reserved3, + bool $indexed, + int $colIndex, + ?int $bytePos = null + ) { $name = (false !== strpos($name, chr(0x00))) ? substr($name, 0, strpos($name, chr(0x00))) : $name; $this->rawName = $name; @@ -48,8 +67,11 @@ public function __construct(string $name, string $type, int $memAddress, int $le $this->memAddress = $memAddress; $this->length = $length; $this->decimalCount = $decimalCount; + $this->reserved1 = $reserved1; $this->workAreaID = $workAreaID; + $this->reserved2 = $reserved2; $this->setFields = $setFields; + $this->reserved3 = $reserved3; $this->indexed = $indexed; $this->colIndex = $colIndex; $this->bytePos = $bytePos; @@ -80,4 +102,19 @@ public function toString() { return $this->name; } + + public function getReserved1() + { + return $this->reserved1; + } + + public function getReserved2() + { + return $this->reserved2; + } + + public function getReserved3() + { + return $this->reserved3; + } } diff --git a/src/XBase/Column/VisualFoxproColumn.php b/src/XBase/Column/VisualFoxproColumn.php new file mode 100644 index 0000000..95aa85c --- /dev/null +++ b/src/XBase/Column/VisualFoxproColumn.php @@ -0,0 +1,19 @@ +type) { + case FieldType::BLOB: + case FieldType::MEMO: + return 4; + default: + return parent::getDataLength(); + } + } +} diff --git a/src/XBase/Memo/MemoFactory.php b/src/XBase/Memo/MemoFactory.php index 6b11b7f..2690a5d 100644 --- a/src/XBase/Memo/MemoFactory.php +++ b/src/XBase/Memo/MemoFactory.php @@ -24,7 +24,7 @@ public static function create(Table $table): ?MemoInterface } $memoFilepath = $fileInfo['dirname'].DIRECTORY_SEPARATOR.$fileInfo['filename'].$memoExt; if (!file_exists($memoFilepath)) { - return null; + return null; //todo create file? } return $refClass->newInstance($memoFilepath, $table->getConvertFrom()); diff --git a/src/XBase/Record/AbstractRecord.php b/src/XBase/Record/AbstractRecord.php index 8f382a5..f96bfbe 100644 --- a/src/XBase/Record/AbstractRecord.php +++ b/src/XBase/Record/AbstractRecord.php @@ -83,6 +83,11 @@ public function isInserted() return $this->inserted; } + public function setInserted(bool $inserted): void + { + $this->inserted = $inserted; + } + /** * @return ColumnInterface[] */ @@ -399,16 +404,16 @@ public function setObject(ColumnInterface $column, $value) case FieldType::CHAR: $this->setString($column, $value); return false; - case FieldType::DOUBLE: - case FieldType::FLOAT: - $this->setFloat($column, $value); - return false; +// case FieldType::DOUBLE: +// case FieldType::FLOAT: +// $this->setFloat($column, $value); +// return false; case FieldType::DATE: $this->setDate($column, $value); return false; - case FieldType::DATETIME: - $this->setDateTime($column, $value); - return false; +// case FieldType::DATETIME: +// $this->setDateTime($column, $value); +// return false; case FieldType::LOGICAL: $this->setBoolean($column, $value); return false; @@ -439,6 +444,8 @@ public function setDate(ColumnInterface $column, $value) if ($value instanceof \DateTimeInterface) { $this->forceSetString($column, $value->format('Ymd')); return false; + } elseif (is_int($value)) { + $value = date('Ymd', $value); } if (0 == strlen($value)) { @@ -446,7 +453,7 @@ public function setDate(ColumnInterface $column, $value) return false; } - $this->forceSetString($column, date('Ymd', $value)); + $this->forceSetString($column, $value); return true; } diff --git a/src/XBase/Record/VisualFoxproRecord.php b/src/XBase/Record/VisualFoxproRecord.php index d55ab1c..facacbe 100644 --- a/src/XBase/Record/VisualFoxproRecord.php +++ b/src/XBase/Record/VisualFoxproRecord.php @@ -34,6 +34,27 @@ public function getObject(ColumnInterface $column) } } + public function setObject(ColumnInterface $column, $value) + { + switch ($column->getType()) { + case FieldType::INTEGER: + return $this->setInt($column, $value); + case FieldType::DOUBLE: + return $this->setDouble($column, $value); + case FieldType::DATETIME: + return $this->setDateTime($column, $value); + case FieldType::CURRENCY: + return $this->setCurrency($column, $value); + case FieldType::FLOAT: + return $this->setFloat($column, $value); + case FieldType::VAR_FIELD: + case FieldType::VARBINARY: + return $this->setVarchar($column, $value); + default: + return parent::setObject($column, $value); + } + } + public function getGeneral(string $columnName) { $data = unpack('L', $this->choppedData[$columnName]); @@ -67,6 +88,26 @@ public function getInt(string $columnName) return $ret; } + /** + * @param $value + * + * @return bool + */ + public function setInt(ColumnInterface $column, $value) + { + if (FieldType::INTEGER !== $column->getType()) { + trigger_error($column->getName().' is not a Number column', E_USER_ERROR); + } + + if (0 == strlen($value)) { + $this->forceSetString($column, ''); + return false; + } + + $value = str_replace(',', '.', $value); + $this->forceSetString($column, number_format($value, $column->getDecimalCount(), '.', '')); + } + /** * @return int */ @@ -83,6 +124,13 @@ public function getDouble(string $columnName) return 0; } + public function setDouble(ColumnInterface $column, $value): self + { + //todo + + return $this; + } + public function getCurrency(string $columnName) { $s = $this->choppedData[$columnName]; @@ -96,6 +144,13 @@ public function getCurrency(string $columnName) return 0; } + private function setCurrency(ColumnInterface $column, $value): self + { + //todo + + return $this; + } + public function getVarchar(string $columnName) { $s = $this->forceGetString($columnName); @@ -105,6 +160,13 @@ public function getVarchar(string $columnName) return $s; } + private function setVarchar(ColumnInterface $column, $value): self + { + //todo + + return $this; + } + public function getVarbinary(string $columnName) { $s = $this->forceGetString($columnName); @@ -121,7 +183,7 @@ public function getVarbinary(string $columnName) */ public function setDateTime(ColumnInterface $column, $value) { - if (FieldType::DATETIME != $column->getType()) { + if (FieldType::DATETIME !== $column->getType()) { trigger_error($column->getName().' is not a DateTime column', E_USER_ERROR); } @@ -148,7 +210,7 @@ public function setDateTime(ColumnInterface $column, $value) */ public function setFloat(ColumnInterface $column, $value) { - if (FieldType::FLOAT != $column->getType()) { + if (FieldType::FLOAT !== $column->getType()) { trigger_error($column->getName().' is not a Float column', E_USER_ERROR); } @@ -161,26 +223,6 @@ public function setFloat(ColumnInterface $column, $value) $this->forceSetString($column, $value); } - /** - * @param $value - * - * @return bool - */ - public function setInt(ColumnInterface $column, $value) - { - if (FieldType::NUMERIC != $column->getType()) { - trigger_error($column->getName().' is not a Number column', E_USER_ERROR); - } - - if (0 == strlen($value)) { - $this->forceSetString($column, ''); - return false; - } - - $value = str_replace(',', '.', $value); - $this->forceSetString($column, number_format($value, $column->getDecimalCount(), '.', '')); - } - /** * @return bool|float|int */ diff --git a/src/XBase/Table.php b/src/XBase/Table.php index e2b088e..adc5312 100755 --- a/src/XBase/Table.php +++ b/src/XBase/Table.php @@ -37,13 +37,13 @@ class Table /** @var int */ protected $filePos = 0; - /** @var int */ + /** @var int Current record position. */ protected $recordPos = -1; /** @var int */ protected $deleteCount = 0; - /** @var Record */ + /** @var RecordInterface|null */ protected $record; /** @var string|null */ @@ -135,7 +135,6 @@ class Table /** * Table constructor. * - * @param string $filepath * @param array|null $availableColumns * @param string|null $convertFrom Encoding of file * @@ -539,33 +538,21 @@ public function getModifyDate() return $this->modifyDate; } - /** - * @return bool - */ public function isInTransaction(): bool { return $this->inTransaction; } - /** - * @return bool - */ public function isEncrypted(): bool { return $this->encrypted; } - /** - * @return string - */ public function getMdxFlag(): string { return $this->mdxFlag; } - /** - * @return int - */ public function getHeaderLength(): int { return $this->headerLength; diff --git a/src/XBase/WritableTable.php b/src/XBase/WritableTable.php index 2ae31b4..f87edcc 100644 --- a/src/XBase/WritableTable.php +++ b/src/XBase/WritableTable.php @@ -4,6 +4,9 @@ use XBase\Column\DBaseColumn; use XBase\Enum\TableType; +use XBase\Exception\TableException; +use XBase\Record\RecordFactory; +use XBase\Record\RecordInterface; use XBase\Stream\Stream; class WritableTable extends Table @@ -42,7 +45,7 @@ public function cloneFrom(Table $table) public function create($filename, $fields) { if (!$fields || !is_array($fields)) { - throw new Exception\TableException('cannot create xbase with no fields', $this->filepath); + throw new TableException('cannot create xbase with no fields', $this->filepath); } $recordByteLength = 1; @@ -52,7 +55,7 @@ public function create($filename, $fields) foreach ($fields as $field) { if (!$field || !is_array($field) || sizeof($field) < 2) { - throw new Exception\TableException('fields argument error, must be array of arrays', $this->filepath); + throw new TableException('fields argument error, must be array of arrays', $this->filepath); } $column = new DBaseColumn($field[0], $field[1], 0, @$field[2], @$field[3], 0, 0, 0, 0, 0, 0, $i, $recordByteLength); $recordByteLength += $column->getDataLength(); @@ -71,7 +74,7 @@ public function create($filename, $fields) $result->mdxFlag = chr(0); $result->languageCode = chr(0); $result->columns = $columns; - $result->columnNames = $columnNames; +// $result->columnNames = $columnNames; $result->backlist = ''; $result->foxpro = false; @@ -107,9 +110,9 @@ public function openWrite($filename = false, $overwrite = false) return false != $this->fp; } - public function writeHeader() + public function writeHeader(): void { - $this->headerLength = ($this->foxpro ? 296 : 33) + ($this->getColumnCount() * 32); + $this->headerLength = ($this->isFoxpro() ? 296 : 33) + ($this->getColumnCount() * 32); $this->fp->seek(0); @@ -128,52 +131,77 @@ public function writeHeader() $this->fp->write(str_pad('', 2, chr(0))); foreach ($this->columns as $column) { - $this->fp->write(str_pad(substr($column->getRawName(), 0, 11), 11, chr(0))); - $this->fp->write($column->getType()); - $this->fp->writeUInt($column->getMemAddress()); - $this->fp->writeUChar($column->getDataLength()); - $this->fp->writeUChar($column->getDecimalCount()); - $this->fp->write(str_pad('', 2, chr(0))); - $this->fp->writeUChar($column->getWorkAreaID()); - $this->fp->write(str_pad('', 2, chr(0))); - $this->fp->write(chr($column->isSetFields() ? 1 : 0)); - $this->fp->write(str_pad('', 7, chr(0))); - $this->fp->write(chr($column->isIndexed() ? 1 : 0)); + $this->fp->write(str_pad(substr($column->getRawName(), 0, 11), 11, chr(0))); // 0-10 + $this->fp->write($column->getType());// 11 + $this->fp->writeUInt($column->getMemAddress());//12-15 + $this->fp->writeUChar($column->getDataLength());//16 + $this->fp->writeUChar($column->getDecimalCount());//17 + $this->fp->write( + method_exists($column, 'getReserved1') + ? call_user_func([$column, 'getReserved1']) + : str_pad('', 2, chr(0)) + );//18-19 + $this->fp->writeUChar($column->getWorkAreaID());//20 + $this->fp->write( + method_exists($column, 'getReserved2') + ? call_user_func([$column, 'getReserved2']) + : str_pad('', 2, chr(0)) + );//21-22 + $this->fp->write(chr($column->isSetFields() ? 1 : 0));//23 + $this->fp->write( + method_exists($column, 'getReserved3') + ? call_user_func([$column, 'getReserved3']) + : str_pad('', 7, chr(0)) + );//24-30 + $this->fp->write(chr($column->isIndexed() ? 1 : 0));//31 } + $this->fp->writeUChar(0x0d); + if ($this->foxpro) { $this->fp->write(str_pad($this->backlist, 263, ' ')); } - - $this->fp->writeUChar(0x0d); } /** - * @return Record + * @return RecordInterface */ public function appendRecord() { - $this->record = new Record($this, $this->recordCount); - $this->recordCount += 1; + $this->recordPos = $this->recordCount++; + $this->record = RecordFactory::create($this, $this->recordPos); return $this->record; } - public function writeRecord() + public function writeRecord(): void { - $p = $this->fp->seek($this->headerLength + ($this->record->getRecordIndex() * $this->recordByteLength)); + if (!$this->record) { + return; + } + + $offset = $this->headerLength + ($this->record->getRecordIndex() * $this->recordByteLength); + $this->fp->seek($offset); $data = $this->record->serializeRawData(); // removed referencing - $p = $this->fp->write($data); + $this->fp->write($data); if ($this->record->isInserted()) { $this->writeHeader(); } $this->fp->flush(); + + $this->record->setInserted(false); } - public function deleteRecord() + public function deleteRecord(): void { + if ($this->record->isInserted()) { + $this->record = null; + $this->recordPos = -1; + return; + } + $this->record->setDeleted(true); $this->fp->seek($this->headerLength + ($this->record->getRecordIndex() * $this->recordByteLength)); @@ -214,88 +242,4 @@ public function pack() $this->fp->truncate($this->headerLength + ($this->recordCount * $this->recordByteLength)); } - -// /** -// * {{@inheritdoc}} -// */ -// protected function writes($buf) -// { -// return fwrite($this->fp, $buf); -// } -// -// /** -// * {{@inheritdoc}} -// */ -// protected function write($buf) -// { -// return fwrite($this->fp, $buf); -// } -// -// /** -// * {{@inheritdoc}} -// */ -// protected function writeString($string) -// { -// return $this->fp->writes($string); -// } -// -// /** -// * {@inheritdoc} -// */ -// protected function writeChar($c) -// { -// $buf = pack("C", $c); -// -// return $this->fp->writes($buf); -// } -// -// /** -// * {@inheritdoc} -// */ -// protected function writeShort($s) -// { -// $buf = pack("S", $s); -// -// return $this->fp->writes($buf); -// } -// -// /** -// * {@inheritdoc} -// */ -// protected function writeInt($i) -// { -// $buf = pack("I", $i); -// -// return $this->fp->writes($buf); -// } -// -// /** -// * {@inheritdoc} -// */ -// protected function writeLong($l) -// { -// $buf = pack("L", $l); -// -// return $this->fp->writes($buf); -// } -// -// /** -// * {@inheritdoc} -// */ -// protected function write3ByteDate($d) -// { -// $t = getdate($d); -// -// return $this->fp->writeChar($t["year"] % 1000) + $this->fp->writeChar($t["mon"]) + $this->fp->writeChar($t["mday"]); -// } -// -// /** -// * {@inheritdoc} -// */ -// protected function write4ByteDate($d) -// { -// $t = getdate($d); -// -// return $this->fp->writeShort($t["year"]) + $this->fp->writeChar($t["mon"]) + $this->fp->writeChar($t["mday"]); -// } } diff --git a/tests/WritableTableTest.php b/tests/WritableTableTest.php index 86acb32..1f75e71 100644 --- a/tests/WritableTableTest.php +++ b/tests/WritableTableTest.php @@ -3,8 +3,9 @@ namespace XBase\Tests; use PHPUnit\Framework\TestCase; -use XBase\Record; +use XBase\Enum\TableType; use XBase\Record\DBaseRecord; +use XBase\Record\VisualFoxproRecord; use XBase\Table; use XBase\WritableTable; @@ -15,9 +16,19 @@ class WritableTableTest extends TestCase private function duplicateFile(string $file): string { $info = pathinfo($file); - $newName = uniqid($info['filename']); + $newName = uniqid($info['filename'].'_'); $copyTo = "{$info['dirname']}/$newName.{$info['extension']}"; self::assertTrue(copy($file, $copyTo)); + + $memoExt = ['fpt']; + foreach ($memoExt as $ext) { + $memoFile = "{$info['dirname']}/{$info['filename']}.$ext"; + if (file_exists($memoFile)) { + $memoFileCopy = "{$info['dirname']}/$newName.$ext"; + self::assertTrue(copy($memoFile, $memoFileCopy)); + } + } + return $copyTo; } @@ -51,24 +62,33 @@ public function testAppendRecord(): void $copyTo = $this->duplicateFile(self::FILEPATH); try { $table = new WritableTable($copyTo, null, 'cp866'); + + self::assertSame( + $table->getHeaderLength() + ($table->getRecordCount() * $table->getRecordByteLength()) + 1, // Last byte must be 0x1A + filesize($copyTo) + ); + self::assertSame(TableType::DBASE_III_PLUS_NOMEMO, $table->getVersion()); + self::assertEquals(10, $table->getRecordCount()); + $table->openWrite(); $record = $table->appendRecord(); - self::assertInstanceOf(Record::class, $record); - - $record->setInt($record->getColumn('regn'), 3); - $record->setString($record->getColumn('plan'), 'Д'); - $record->setString($record->getColumn('num_sc'), '10101'); - $record->setString($record->getColumn('a_p'), '3'); - $record->setInt($record->getColumn('vr'), 100); - $record->setInt($record->getColumn('vv'), 200); - $record->setInt($record->getColumn('vitg'), 300.0201); - $record->setDate($record->getColumn('dt'), new \DateTime('1970-01-03')); - $record->setInt($record->getColumn('priz'), 2); + self::assertInstanceOf(DBaseRecord::class, $record); + + $record->setNum($table->getColumn('regn'), 3); + $record->setString($table->getColumn('plan'), 'Д'); + $record->setString($table->getColumn('num_sc'), '10101'); + $record->setString($table->getColumn('a_p'), '3'); + $record->setNum($table->getColumn('vr'), 100); + $record->setNum($table->getColumn('vv'), 200); + $record->setNum($table->getColumn('vitg'), 300.0201); + $record->setDate($table->getColumn('dt'), new \DateTime('1970-01-03')); + $record->setNum($table->getColumn('priz'), 2); $table->writeRecord(); + $table->pack(); $table->close(); clearstatcache(); - $expectedSize = $table->headerLength + ($table->recordCount * $table->recordByteLength); // Last byte must be 0x1A + $expectedSize = $table->getHeaderLength() + ($table->getRecordCount() * $table->getRecordByteLength()); // Last byte must be 0x1A self::assertSame($expectedSize, filesize($copyTo)); $table = new Table($copyTo, null, 'cp866'); @@ -183,4 +203,114 @@ public function testIssue78(): void unlink($copyTo); } } + + /** + * Not set current record. Should not fall + */ + public function testVisualFoxProWriteCopy(): void + { + $original = __DIR__.'/Resources/foxpro/vfp.dbf'; + $copyTo = $this->duplicateFile($original); + $table = new WritableTable($copyTo); + $table->writeRecord(); + $table->close(); + self::assertFileEquals($original, $copyTo); + } + + /** + * Append and delete record immediately. + */ + public function testVisualFoxProWriteCopy2(): void + { + $original = __DIR__.'/Resources/foxpro/vfp.dbf'; + $copyTo = $this->duplicateFile($original); + $table = new WritableTable($copyTo); + $table->appendRecord(); + $table->deleteRecord(); + $table->writeRecord(); + $table->close(); + self::assertFileEquals($original, $copyTo); + } + + /** + * Append and delete record immediately. + */ + public function testVisualFoxProWriteCopy3(): void + { + $copyTo = $this->duplicateFile(__DIR__.'/Resources/foxpro/vfp.dbf'); + try { + $table = new WritableTable($copyTo); + self::assertSame(3, $table->getRecordCount()); + $table->openWrite(); + $table->appendRecord(); + $table->writeRecord(); + $table->deleteRecord(); + $table->pack(); + $table->close(); + self::assertSame(3, $table->getRecordCount()); + } finally { + unlink($copyTo); + } + } + + public function testVisualFoxProAppendRecord(): void + { + $copyTo = $this->duplicateFile(__DIR__.'/Resources/foxpro/vfp.dbf'); + try { + $table = new WritableTable($copyTo); + self::assertEquals(3, $table->getRecordCount()); + self::assertEquals(TableType::VISUAL_FOXPRO_VAR, $table->getVersion()); + + $table->openWrite(); + /** @var VisualFoxproRecord $record */ + $record = $table->appendRecord(); + self::assertInstanceOf(VisualFoxproRecord::class, $record); + $record->setObject($table->getColumn('name'), 'gam6itko'); + $record->setObject($table->getColumn('birthday'), '1988-10-10'); + $record->setObject($table->getColumn('is_man'), true); +// $record->setObject($table->getColumn('bio'), 'another time'); + $record->setObject($table->getColumn('money'), 100.10); +// $record->setObject($table->getColumn('image'), ); + $record->setObject($table->getColumn('rate'), 10.55); +// $record->setObject($table->getColumn('general'), ); +// $record->setObject($table->getColumn('blob'), ); +// $record->setObject($table->getColumn('currency'), ); + $record->setObject($table->getColumn('datetime'), new \DateTime('2020-09-10')); + $record->setObject($table->getColumn('double'), 3.1415); + $record->setObject($table->getColumn('integer'), 3); + $record->setObject($table->getColumn('varchar'), 'varchar'); +// $record->setInt($table->getColumn('name_bin'), ); +// $record->setInt($table->getColumn('bio_bin'), ); +// $record->setInt($table->getColumn('varbinary'), ); +// $record->setInt($table->getColumn('varchar_bi'), ); + $table->writeRecord(); + $table->close(); + + $table = new Table($copyTo); + self::assertEquals(4, $table->getRecordCount()); + + $record = $table->pickRecord(3); + $record->getObject($table->getColumn('name'), 'gam6itko'); + $record->getObject($table->getColumn('birthday'), '1988-10-10'); + $record->getObject($table->getColumn('is_man'), true); +// $record->getObject($table->getColumn('bio'), 'another time'); + $record->getObject($table->getColumn('money'), 100.10); +// $record->getObject($table->getColumn('image'), ); + $record->getObject($table->getColumn('rate'), 10.55); +// $record->getObject($table->getColumn('general'), ); +// $record->getObject($table->getColumn('blob'), ); +// $record->getObject($table->getColumn('currency'), ); + $record->getObject($table->getColumn('datetime'), new \DateTime('2020-09-10')); + $record->getObject($table->getColumn('double'), 3.1415); + $record->getObject($table->getColumn('integer'), 3); + $record->getObject($table->getColumn('varchar'), 'varchar'); +// $record->getObject($table->getColumn('name_bin'), ); +// $record->getObject($table->getColumn('bio_bin'), ); +// $record->getObject($table->getColumn('varbinary'), ); +// $record->getObject($table->getColumn('varchar_bi'), ); + $table->close(); + } finally { + unlink($copyTo); + } + } }