rafaelnajera/datatable

此包已被弃用且不再维护。作者建议使用thomas-institut/datatable包。

简单数据表界面

2.0.1 2024-01-30 10:52 UTC

This package is auto-updated.

Last update: 2024-01-30 10:52:59 UTC


README

Latest Stable Version License

此包定义了一个接口,用于抽象基于具有唯一整数ID作为键的SQL表的数据访问和操作,并提供内存和MySQL实现。目的是将基本数据函数从实际数据库细节中解耦,并允许通过使用内存表进行更快的测试。

安装

使用以下命令安装最新版本:

$ composer require thomas-institut/datatable

使用方法

DataTable

主要组件是DataTable接口,它捕获了具有唯一整数ID的SQL表的基本功能。实现处理底层存储,可以在不同的DataTable实例之间共享。提供了基本的ID生成机制作为顺序ID的替代方案。

$dt = new DataTableImplementationClass(...) 

DataTable对象还实现了ArrayAccessIteratorAggregateLoggerAwareInterfaceErrorReporter接口。

默认的ID生成机制的行为与数据库中的自增类似,但它不需要数据库干预。可以通过setIdGenerator设置替代的ID生成器。

此包中提供的MySqlDataTable实现还可以将ID生成推迟到MySQL的AUTO INCREMENT功能,这比DataTable的默认实现更受欢迎。

提供了一个随机ID生成器。此生成器将尝试在两个给定值之间生成随机ID,最多尝试指定次数,之后将默认为当前最大ID加1。

$dt->setIdGenerator(new RandomIdGenerator($min, $max, $maxAttempts));

如果选择了合适的$min$max$maxAttempts值,则随机ID生成器几乎不可能回到默认值。

错误处理和报告

无效参数错误由自定义异常处理(请参阅每个方法的文档以获取详细信息),所有其他问题通常会导致抛出RunTimeException。

可以通过调用getErrorCodegetErrorMessage方法检查最新错误。这两个方法定义在ErrorReporter接口中。

根据LoggerAwareInteface,还可以设置PSR Logger,并且实现通常应该在此处报告所有错误。

行创建

$newRow = [ 'field1' => 'exampleStringValue', // or  
            'field2' => null, 
            'field3' => true, // or false
            'field4' => $someIntegerVariable
            // ... 
             'fieldN' => $nthValue ];  
             
$newId  = $dt->createRow($newRow);  

// $newId is unique within the table

如果用于创建的行中存在ID,则将使用该ID作为新ID,如果该ID正在使用中,则将抛出RowAlreadyExists异常。

默认的ID字段/列名称为id,如果实际存储中的底层表使用不同的名称,则可以设置setIdColumnName,通常在构造之后进行

$dt = new DataTableImplementation();
$dt->setIdColumnName('row_id'); 

$dt->getIdColumnName();  // 'row_id'

在DataTable中设置列名不会更改底层数据库中的任何内容。它只告诉DataTable实际数据库ID的名称。

也可以使用数组访问来创建新行

$dt[] = $newRow; 

// new row with a given id 
$dt[$desiredId] = $newRow;
// but this updates the row if $desiredId already exists

在创建行时可以使用任意数量的字段/列和类型,只要它们与实现和实际存储相匹配。忽略额外数据或抛出错误由实现自行决定。

读取/搜索行

检查行是否存在

$result = $dt->rowExists($rowId);

获取特定行

$row = $dt->getRow($rowId);  
//  $row === [ 'id' => $rowId, 'col1' => value, .... 'colN' => value]; 

// OR

$row = $dt[$rowId];
  
// both throw a RowDoesNotExist exception if the row does not exist

获取所有行

$rows = $dt->getAllRows();

所有可能返回多行的方法都返回一个DataTableIterator对象。这是一个正常的PHP迭代器,可以在foreach语句中使用,并且扩展了具有返回结果数目的count()方法。

迭代器还提供了一个方便的方法getFirst(),它返回集合中的第一个结果。然而,无法保证在getFirst()之后对迭代器执行foreach语句将工作,或者getFirst()将在foreach之后工作,因为某些实现中可能无法回滚。

$rows = $dt->getAllRows();

$numRows = $rows->count();

// EITHER 

foreach($rows as $row) {
   // do something ...
} 

// OR

$firstRow = $rows->getFirst(); // null if there are no rows in the result set
    

search方法根据以下规则在DataTable上执行基于搜索条件数组和搜索类型的通用搜索

public function search(array $searchSpecArray, int $searchType = self::SEARCH_AND, int $maxResults = 0) : array;

/**
  * Searches the datatable according to the given $searchSpec
  *
  * $searchSpecArray is an array of conditions.
  *
  * If $searchType is SEARCH_AND, the row must satisfy:
  *      $searchSpecArray[0] && $searchSpecArray[1] && ...  && $searchSpecArray[n]
  *
  * if  $searchType is SEARCH_OR, the row must satisfy the negation of the spec:
  *
  *      $searchSpecArray[0] || $searchSpecArray[1] || ...  || $searchSpecArray[n]
  *
  *
  * A condition is an array of the form:
  *
  *  $condition = [
  *      'column' => 'columnName',
  *      'condition' => one of (EQUAL_TO, NOT_EQUAL_TO, LESS_THAN, LESS_OR_EQUAL_TO, GREATER_THAN, GREATER_OR_EQUAL_TO)
  *      'value' => someValue
  * ]
  *
  * Notice that each condition type has a negation:
  *      EQUAL_TO  <==> NOT_EQUAL_TO
  *      LESS_THAN  <==>  GREATER_OR_EQUAL_TO
  *      LESS_OR_EQUAL_TO <==> GREATER_THAN
  *
  * if $maxResults > 0, an array of max $maxResults will be returned
  * if $maxResults <= 0, all results will be returned

通常,可以使用更简单的实用方法findRows进行简单的列和值匹配。

public function findRows(array $rowToMatch, int $maxResults = 0) : array;

如果行与$rowToMatch中的每个键的值匹配,则它将作为结果集的一部分返回。这相当于对$rowToMatch中的每个键执行AND搜索,并且条件为EQUAL_TO。

更新行

$dt->updateRow($row);

// OR 

$dt[$rowId] = $row;

updateRow中,给定的行必须有一个id字段,它对应于表中的一行,否则将抛出RowDoesNotExist异常。在数组访问版本中,无论给定的行中是否有id字段,都将使用给定的$rowId

仅更新$row中的字段。如果底层数据库模式期望这些列的值,则可能产生错误的不完整行。

删除行

$result = $dt->deleteRow($rowId);

// OR

unset($dt[$rowId]);

结果是受影响的列数,如果行最初不存在,则结果为0。

事务

如果存在,DataTable提供基本接口来访问底层数据库事务功能。

检查是否支持事务

$supported = $dt->supportsTransactions(); // true if supported

如果支持事务,可以使用startTransaction()开始事务,并使用commit()rollBack()结束事务。

if($dt->supportsTransactions()){
  if ($dt->startTransaction()) {
  
    // create, update,delete rows ...
    // decide whether to commit or rollback

    if ($goAheadWithCommit)  {  
       if ($dt->commit()){  
          // all went well, changes are committed
       } else {
          // error during commit
          $errorMessage = $dt->getErrorMessage();
          $errorCode = $dt->getErrorCode();
       }
    } else {  // roll back
       if ($dt->rollBack() {
          // rollBack done, changes to the database not saved
       } else {
          // error during rollBack       
          $errorMessage = $dt->getErrorMessage();
          $errorCode = $dt->getErrorCode();
       }
    }
  } else {
     // error starting transaction
     $errorMessage = $dt->getErrorMessage();
     $errorCode = $dt->getErrorCode();
  }
}

还有一个方便的方法可以让DataTable检查底层数据库是否处于事务中

$result = $dt->isUnderlyingDatabaseInTransaction();

在处理事务时需要格外小心,特别是如果数据库连接在多个DataTable之间共享。如果底层数据库报告正在执行事务(这可能可靠也可能不可靠,取决于数据库),DataTable不会开始事务。此外,只能在对事务发起的DataTable上执行提交。

如果DataTable不支持事务,则startTransaction()commit()rollBack()将始终返回false

内存中的DataTable

使用简单PHP数组实现的DataTable实现,没有存储。这使得可以在不设置数据库的情况下对数据表进行测试。

MySQLDataTable

使用MySQL表的DataTable实现。

$dt = new MySqlDataTable($pdoDatabaseConnection, $mySqlTableName, $useAutoInc, $idColumnName);

MySqlDataTable假设存在一个至少有一个名为$idColumnName(默认为'id')的整数id列的表。

如果 $useAutoInc 为真,MySqlDataTable 假定 id 列具有 AUTO_INCREMENT 属性,并将创建行以便 MySQL 负责生成 ID。否则,MySqlDataTable 本身负责生成增量 ID。

为了与该库的先前版本兼容,$useAutoInc 默认为 false。然而,建议您使用 MySQL 自增功能。在存在多个并发调用 createRow 的场景中,DataTable 的内部 ID 生成器可能无法生成唯一的 ID。

MySQL 中的表可以拥有任意数量和类型的额外列。只要 createRowupdateRow 调用与列名和类型一致,一切应该运行正常。您也可以在 MySQL 中定义默认值,并在调用 createRow 时省略这些值。

MySqlDataTableWithRandomIds

MySqlDatable 相同,但使用随机 ID 生成器。

MySqlUnitemporalDataTable

一个带有时间标记行的 MySQL 表。每一行不仅有一个唯一的 ID,还有一个有效的从和到时间。当使用正常的 DataTable 方法时,MySQLUnitemporalDataTable 的行为与 MySqlDataTable 完全相同,但它不会删除任何行,只是使它们无效。

有一组时间方法用于创建、读取、更新和删除数据的先前版本。例如

$dt = new MySqlUnitemporalDataTable($pdoDatabaseConnection, $mySqlTableName);


$oldRow = $dt->getRowWithTime($rowId, $timeString);

$timeString 是一个格式化为有效 MySQL 日期时间的字符串,例如 '2018-01-01 12:00:00.123123' 使用 TimeString 类的静态方法从 MySQL 日期和日期时间字符串以及带或不带微秒的 UNIX 时间戳生成此类字符串。

底层 MySQL 表必须有两个日期时间字段:valid_fromvalid_until

用户负责设置 PDO 连接,以便使用具有时间参数的所有查询的时间区域。