Skip to content

Commit

Permalink
Issue #6 Fix Visual FoxPro interpreting problem
Browse files Browse the repository at this point in the history
  • Loading branch information
majkel89 committed Jan 22, 2017
1 parent 5c23c8e commit 2cd356f
Show file tree
Hide file tree
Showing 6 changed files with 187 additions and 3 deletions.
11 changes: 8 additions & 3 deletions src/Format.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ abstract class Format {

const AUTO = 'auto';
const DBASE3 = 'dbase3';
const FOXPRO = 'foxpro';

const NAME = 'Abstract DBase Format';

Expand Down Expand Up @@ -445,12 +446,15 @@ protected function readHeader() {

$fieldsSz = $headerSize - $hSz - 1;
$allFields = $file->fread($fieldsSz);
$fieldsCount = floor($fieldsSz / $hSz);

$fSz = static::FIELD_SIZE;
$format = static::FIELD_FORMAT;
for ($index = 0; $index < $fieldsCount; ++$index) {
$data = unpack($format, substr($allFields, $index * $fSz, $fSz));
for ($offset = 0; $offset < $fieldsSz; $offset += $hSz) {
$fieldData = substr($allFields, $offset, $fSz);
if ($fieldData[0] === "\r") {
break;
}
$data = unpack($format, $fieldData);
$col = strpos($data['n'], "\0");
if ($col !== false) {
$data['n'] = substr($data['n'], 0, $col);
Expand Down Expand Up @@ -539,6 +543,7 @@ protected function createRecord($data) {
public static function getSupportedFormats() {
return array(
Format::DBASE3,
Format::FOXPRO,
);
}

Expand Down
3 changes: 3 additions & 0 deletions src/FormatFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@ public function initializeFormats() {
$this->registerFormat(Format::DBASE3, function ($filePath, $mode) {
return new format\DBase3($filePath, $mode);
});
$this->registerFormat(Format::FOXPRO, function ($filePath, $mode) {
return new format\FoxPro($filePath, $mode);
});
$this->registerFormat(Format::AUTO, function ($filePath, $mode) use (&$self) {
foreach ($self->getFormats() as $name => $generator) {
try {
Expand Down
53 changes: 53 additions & 0 deletions src/format/FoxPro.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php
/**
* Created by PhpStorm.
* User: Michał Kowalik <maf.michal@gmail.com>
* Date: 22.01.17 22:59
*/

namespace org\majkel\dbase\format;

use org\majkel\dbase\Field;
use org\majkel\dbase\Format;

/**
* Class FoxPro
*
* @package org\majkel\dbase\format
*
* @author Michał Kowalik <maf.michal@gmail.com>
*/
class FoxPro extends Format {

const NAME = 'FoxPro';

/**
* {@inheritdoc}
*/
protected function createHeader($data) {
$header = parent::createHeader($data);
return $header->setValid($header->getVersion() & $this->getVersion());
}

/**
* {@inheritdoc}
*/
public function supportsType($type) {
return in_array($type, array(Field::TYPE_CHARACTER, Field::TYPE_DATE,
Field::TYPE_LOGICAL, Field::TYPE_MEMO, Field::TYPE_NUMERIC));
}

/**
* @return string
*/
public function getType() {
return Format::FOXPRO;
}

/**
* @return integer
*/
protected function getVersion() {
return 0x30;
}
}
Binary file added tests/fixtures/issue-6-example-file.dbf
Binary file not shown.
44 changes: 44 additions & 0 deletions tests/integration/Issue6Test.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php
/**
* Created by PhpStorm.
* User: Michał Kowalik <maf.michal@gmail.com>
* Date: 22.01.17 22:10
*/

namespace org\majkel\dbase;

use org\majkel\dbase\tests\utils\TestBase;

/**
* Class Issue6Test
*
* @author Michał Kowalik <maf.michal@gmail.com>
*
* @coversDefaultClass \org\majkel\dbase\format\FoxPro
*/
class Issue6Test extends TestBase
{
/**
* @test
* @throws Exception
* @throws \PHPUnit_Framework_AssertionFailedError
*/
public function testLoadFoxProFile()
{
$table = Table::fromFile("tests/fixtures/issue-6-example-file.dbf");
self::assertSame(3, $table->getRecordsCount());
self::assertSame(8, $table->getFieldsCount());
self::assertSame($table->getField('DFD')->getType(), Field::TYPE_CHARACTER);
self::assertSame($table->getField('FDA')->getType(), Field::TYPE_CHARACTER);
self::assertSame($table->getField('FDAS')->getType(), Field::TYPE_CHARACTER);
self::assertSame($table->getField('HG')->getType(), Field::TYPE_CHARACTER);
self::assertSame($table->getField('T43')->getType(), Field::TYPE_CHARACTER);
self::assertSame($table->getField('LK')->getType(), Field::TYPE_CHARACTER);
self::assertSame($table->getField('POI')->getType(), Field::TYPE_CHARACTER);
self::assertSame($table->getField('OIU')->getType(), Field::TYPE_CHARACTER);
foreach ($table as $row) {
/** @var Record $row */
self::assertNotEmpty($row->toArray());
}
}
}
79 changes: 79 additions & 0 deletions tests/unit/format/FoxProTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<?php

/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/

namespace org\majkel\dbase\format;

use org\majkel\dbase\Format;
use org\majkel\dbase\tests\utils\AbstractFormatTest;
use org\majkel\dbase\Field;

/**
* FoxPro format tests
*
* @author majkel
*
* @coversDefaultClass \org\majkel\dbase\format\FoxPro
*/
class FoxProTest extends AbstractFormatTest {

const CLS = '\org\majkel\dbase\format\FoxPro';

/**
* {@inheritdoc}
*/
protected function getFormatObject() {
return $this->mock(self::CLS)->new();
}

/**
* {@inheritdoc}
*/
protected function getSupportedTypes() {
return array(
Field::TYPE_CHARACTER, Field::TYPE_DATE, Field::TYPE_LOGICAL,
Field::TYPE_MEMO, Field::TYPE_NUMERIC
);
}

/**
* @covers ::createHeader
*/
public function testCreateHeader() {
$format = $this->getFormatObject();
$header = $this->reflect($format)->createHeader($this->getHeaderData(array(
'v' => 30,
)));
self::assertTrue($header->isValid());
}

/**
* @covers ::createHeader
*/
public function testCreateHeaderUnknownFormat() {
$format = $this->getFormatObject();
$header = $this->reflect($format)->createHeader($this->getHeaderData(array(
'v' => 666,
)));
self::assertTrue($header->isValid());
}

/**
* @covers ::getName
*/
public function testGetName() {
self::assertSame('FoxPro', $this->getFormatObject()->getName());
}

/**
* @covers ::getType
*/
public function testGetType() {
self::assertSame(Format::FOXPRO, $this->getFormatObject()->getType());
}

}

0 comments on commit 2cd356f

Please sign in to comment.