Unit of Workパターンを調べましたか?
これは、どのように開始するかの非常に大雑把な例です。
基本的な UnitOfWork コンテナー。
class UnitOfWork
{
protected $entities = array();
protected $completed = array();
final public function addEntity( IWorkUnitEntity $entity )
{
$this->entities[] = $entity;
}
final public function execute()
{
try {
foreach ( $this->entities as $entity )
{
$entity->execute();
$completed[] = $entity;
}
}
catch ( UnitOfWorkRollbackException $e )
{
$this->rollbackCompleted();
}
return $this->commitAll();
}
protected function rollbackCompleted()
{
while ( $entity = array_pop( $this->completed ) )
{
$entity->rollback();
}
}
protected function commitAll()
{
try {
foreach ( $this->entities as $entity )
{
$entity->commit();
}
}
catch ( UnitOfWorkRollbackException $e )
{
$this->rollbackCompleted();
return false;
}
return true;
}
}
それを助けるためのいくつかの追加機能
class UnitOfWorkRollbackException extends Exception {};
interface IWorkUnitEntity
{
public function execute();
public function rollback();
}
さて、作業エンティティの例
class FileMoverEntity implements IWorkUnitEntity
{
protected
$source
, $destination
, $newName
;
public function __construct( $source, $destination, $newName = null )
{
$this->source = $source;
$this->destination = dirname( $destination );
$this->newName = $newName;
}
public function execute()
{
if ( is_readable( $this->source ) && is_writable( $this->destination ) )
{
return true;
}
throw new UnitOfWorkRollbackException( 'File cannot be moved' );
}
public function commit()
{
$filename = ( null === $this->newName )
? basename( $this->source )
: $this->newName
;
if ( !rename( $this->source, $this->destination . DIRECTORY_SEPARATOR . $filename ) )
{
throw new UnitOfWorkRollbackException( 'File move failed' );
}
}
public function rollback()
{
// Nothing to do here since the file doesn't actually move until commit()
}
}
すべてを一緒に入れて。
$UoW = new UnitOfWork();
$UoW->addEntity( new FileMoverEntity( '/tmp/foo', '/home/me', 'profile.jpg' ) );
$UoW->addEntity( new FileMoverEntity( '/tmp/bar', '/root', 'profile.jpg' ) );
if ( $UoW->execute() )
{
// all operations successful
}
ここでは、クライアント スクリプトがその情報にアクセスできるように、どの例外がスローされたかを追跡するなど、あなたがやりたいことをいくつか行いませんでしたが、おわかりいただけたと思います。そしてもちろん、あらゆる種類の操作 (DB の更新、API 呼び出しなど) の作業エンティティを作成することもできます。
トランザクションセーフテーブルのないデータベースへの接続に関しては、私には洞察がありません。