- Notifications
You must be signed in to change notification settings - Fork22
Library for processing dbase / xbase / dbf database files
License
majkel89/dbase
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
Library for processing dbase tables.
- dBASE III
- dBASE III PLUS
- DBT
- FPT
Using composer to install this library is strongly recommended.
composer require org.majkel/dbase
Then in your script use this line of code
require_once'vendor/autoload.php'
Download library and place it somewhere on disk.
Then in your script use this line of code
require_once'DBASE/LIB/DIR/autoloader.php';
Table object is both array accessible and traversable.You can loop over it as collection or read specific record by it's index.
require_once'vendor/autoload.php'useorg\majkel\dbase\Table;$totalSum =0;$dbf = Table::fromFile('some/table.dbf');foreach ($dbfas$record) {// returns all records includeing deleted onesif (!$record->isDeleted()) {$totalSum +=$record->int_val; }}echo"Total sum is$totalSum, 5th description:{$record[4]['description']}\n";
You can insert records as record object or as an associative array.
Note that insert operation is not atomic. Use transactions to achieve integritysafety.
require_once'vendor/autoload.php'useorg\majkel\dbase\Table;useorg\majkel\dbase\Record;$dbf = Table::fromFile('some/table.dbf');$record =newRecord();$record->fieldBool =true;$record->fieldInt =123;$record->fieldChar ='some text 1';$record->fieldMemo ='some long text';$dbf->insert($record);$dbf->insert(['fieldBool' =>false,'fieldInt' =>321,'fieldChar' =>'some text 2',]);
Dbase and PHP types are automatically converted during fetching and storing of rows.
Dbase type | Type name | Possible values | PHP type |
---|---|---|---|
C | Character | any string | string |
D | Date | DDMMYY | DateTime |
L | Logical | [YTNF?] | boolean |
M | Memo | any string | string |
N | Numeric | [-0-9.] | int / float |
Record is basically ArrayObject. Object that can be treated as array.
require_once'vendor/autoload.php'useorg\majkel\dbase\Table;$dbf = Table::fromFile('some/table.dbf');// fetch first record$record =$dbf[0];echo"int field:{$record->number}\n";// returns integerecho"bool field:{$record->boolean}\n";// returns booleanecho"date field:{$record->date->format('Y-m-d')}\n";// return DateTime objectecho"text field:{$record->text}\n";// returns stringecho"memo field:{$record->memo}\n";// returns string (not entity id)echo"memo field id:{$record->getMemoEntryId('memo')}\n";// returns entity id for memo field `memo`echo"is record deleted:{$record->isDeleted('memo')}\n";// returns whether record is deleted// ... or ...echo"int field:{$record['number']}\n";// returns integerecho"bool field:{$record['boolean']}\n";// returns booleanecho"date field:{$record['date']->format('Y-m-d')}\n";// return DateTime objectecho"text field:{$record['text']}\n";// returns stringecho"memo field:{$record['memo']}\n";// returns string (not entity id)echo"memo field id:{$record->getMemoEntryId('memo')}\n";// returns entity id for memo field `memo`echo"is record deleted:{$record->isDeleted('memo')}\n";// returns whether record is deleted// you can loop over fields in the recordforeach ($recordas$fieldName =>$fieldValue) {echo"$fieldName =$fieldValue\n";}
require_once'vendor/autoload.php'useorg\majkel\dbase\Table;$dbf = Table::fromFile('some/table.dbf');// fetch first record$record =$dbf[0];$record->number =123;$record->boolean =true;$record->date =newDateTime();$record->text ='some text';$record->memo ='some longer text';// ... or ...$record['number'] =123;$record['boolean'] =true;$record['date'] =newDateTime();$record['text'] ='some text';$record['memo'] ='some longer text';
Note that update operation is not atomic. Use transactions to achieve integritysafety.
require_once'vendor/autoload.php'useorg\majkel\dbase\Table;$dbf = Table::fromFile('some/table.dbf');foreach ($dbfas$record) {$record->int_val +=10;$dbf->update($record);// header is updated everytime}
Do not use
Record::setDeleted
to delete records
require_once'vendor/autoload.php'useorg\majkel\dbase\Table;$dbf = Table::fromFile('some/table.dbf');// delete 7th record$dbf->delete(6);// undelete 6th record$dbf->markDelete(5,false);
Transactions can prevent two processes from updating the same file.
When some process cannot acquire lock on the table exception is being thrown.
Transactions can also save you from unnecessary header updates. Header is updated at the endof transaction.
require_once'vendor/autoload.php'useorg\majkel\dbase\Table;$dbf = Table::fromFile('some/table.dbf');// header is updated. Transaction flag is set$dbf->beginTransaction();foreach ($dbfas$record) {$record->int_val +=10;$dbf->update($record);// header is not written}// duplicate last row$dbf->insert($record);// header is not written// header is written, transaction flag is cleared, recond count is updated$dbf->endTransaction();
To construct new table use builder object.
require_once'vendor/autoload.php'useorg\majkel\dbase\Builder;useorg\majkel\dbase\Format;useorg\majkel\dbase\Field;$table = Builder::create() ->setFormatType(Format::DBASE3) ->addField(Field::create(Field::TYPE_CHARACTER)->setName('str')->setLength(15)) ->addField(Field::create(Field::TYPE_LOGICAL)->setName('bool')) ->addField(Field::create(Field::TYPE_NUMERIC)->setName('num')) ->build('destination.dbf');for ($i =1;$i <=3; ++$i) {$table->insert(['str' =>"Str$i",'bool' =>false,'num' =>$i, ]);}
You can create new table form existing table definition.
require_once'vendor/autoload.php'useorg\majkel\dbase\Builder;useorg\majkel\dbase\Format;useorg\majkel\dbase\Field;$table = Builder::fromFile('source.dbf') ->setFormatType(Format::DBASE3) ->addField(Field::create(Field::TYPE_NUMERIC)->setName('newField1')) ->build('destination.dbf');for ($i =1;$i <=3; ++$i) {$table->insert(['oldField1' =>"Str$i",'oldField2' =>false,'newField1' =>$i, ]);}
Although values are automatically converted based on column type sometimes it isnecessary to perform additional processing.To achieve that you can add filters on columns.
require_once'vendor/autoload.php'useorg\majkel\dbase\Builder;useorg\majkel\dbase\filter\TrimFilter;useyour\CurrencyFilter;$dbf = Table::fromFile('some/table.dbf');$dbf->getHeader()->getField('price') ->addFilter(newTrimFilter()) ->addFilter(newCurrencyFilter(',','.'));foreach ($dbfas$record) {// ...}
Filters are applied during loading in the order they are defined.During serialization filters are applied in reversed order.
require_once'vendor/autoload.php'useorg\majkel\dbase\FilterInterface;useorg\majkel\dbase\Field;class CurrencyFilterextends FilterInterface{/** @var string */private$inputDot;/** @var string */private$outputDot;/** * @param string $inputDot * @param string $outputDot */publicfunction__construct($inputDot,$outputDot) {$this->inputDot =$inputDot;$this->outputDot =$outputDot; }/** * From table value to PHP value * * @param mixed $value * @return mixed */publicfunctiontoValue($value) {returnstr_replace($this->inputDot,$this->outputDot,$value); }/** * From PHP value to table value * * @param mixed $value * @return mixed */publicfunctionfromValue($value) {returnstr_replace($this->outputDot,$this->inputDot,$value); }/** * Filter can be applied on string like columns * * @param integer $type * @return boolean */publicfunctionsupportsType($type) {returnin_aray($type, [Field::TYPE_CHARACTER, Field::TYPE_MEMO]); }}
About
Library for processing dbase / xbase / dbf database files