/** @var FileJournal */
protected $fileJournal;
+ /** @var callable */
+ protected $statusWrapper;
+
/** Bitfield flags for supported features */
const ATTR_HEADERS = 1; // files can be tagged with standard HTTP headers
const ATTR_METADATA = 2; // files can be stored with metadata key/values
$this->concurrency = isset( $config['concurrency'] )
? (int)$config['concurrency']
: 50;
+ // @TODO: dependency inject this
+ $this->statusWrapper = [ 'Status', 'wrap' ];
}
/**
*
* a) Create a new file in storage with the contents of a string
* @code
- * array(
+ * [
* 'op' => 'create',
* 'dst' => <storage path>,
* 'content' => <string of new file contents>,
* 'overwrite' => <boolean>,
* 'overwriteSame' => <boolean>,
* 'headers' => <HTTP header name/value map> # since 1.21
- * );
+ * ]
* @endcode
*
* b) Copy a file system file into storage
* @code
- * array(
+ * [
* 'op' => 'store',
* 'src' => <file system path, FSFile, or TempFSFile>,
* 'dst' => <storage path>,
* 'overwrite' => <boolean>,
* 'overwriteSame' => <boolean>,
* 'headers' => <HTTP header name/value map> # since 1.21
- * )
+ * ]
* @endcode
*
* c) Copy a file within storage
* @code
- * array(
+ * [
* 'op' => 'copy',
* 'src' => <storage path>,
* 'dst' => <storage path>,
* 'overwriteSame' => <boolean>,
* 'ignoreMissingSource' => <boolean>, # since 1.21
* 'headers' => <HTTP header name/value map> # since 1.21
- * )
+ * ]
* @endcode
*
* d) Move a file within storage
* @code
- * array(
+ * [
* 'op' => 'move',
* 'src' => <storage path>,
* 'dst' => <storage path>,
* 'overwriteSame' => <boolean>,
* 'ignoreMissingSource' => <boolean>, # since 1.21
* 'headers' => <HTTP header name/value map> # since 1.21
- * )
+ * ]
* @endcode
*
* e) Delete a file within storage
* @code
- * array(
+ * [
* 'op' => 'delete',
* 'src' => <storage path>,
* 'ignoreMissingSource' => <boolean>
- * )
+ * ]
* @endcode
*
* f) Update metadata for a file within storage
* @code
- * array(
+ * [
* 'op' => 'describe',
* 'src' => <storage path>,
* 'headers' => <HTTP header name/value map>
- * )
+ * ]
* @endcode
*
* g) Do nothing (no-op)
* @code
- * array(
+ * [
* 'op' => 'null',
- * )
+ * ]
* @endcode
*
* Boolean flags for operations (operation-specific):
* during the operation. The 'failCount', 'successCount', and 'success' members
* will reflect each operation attempted.
*
- * The status will be "OK" unless:
+ * The StatusValue will be "OK" unless:
* - a) unexpected operation errors occurred (network partitions, disk full...)
* - b) significant operation errors occurred and 'force' was not set
*
* @param array $ops List of operations to execute in order
* @param array $opts Batch operation options
- * @return Status
+ * @return StatusValue
*/
final public function doOperations( array $ops, array $opts = [] ) {
if ( empty( $opts['bypassReadOnly'] ) && $this->isReadOnly() ) {
- return Status::newFatal( 'backend-fail-readonly', $this->name, $this->readOnly );
+ return $this->newStatus( 'backend-fail-readonly', $this->name, $this->readOnly );
}
if ( !count( $ops ) ) {
- return Status::newGood(); // nothing to do
+ return $this->newStatus(); // nothing to do
}
$ops = $this->resolveFSFileObjects( $ops );
*
* @param array $op Operation
* @param array $opts Operation options
- * @return Status
+ * @return StatusValue
*/
final public function doOperation( array $op, array $opts = [] ) {
return $this->doOperations( [ $op ], $opts );
*
* @param array $params Operation parameters
* @param array $opts Operation options
- * @return Status
+ * @return StatusValue
*/
final public function create( array $params, array $opts = [] ) {
return $this->doOperation( [ 'op' => 'create' ] + $params, $opts );
*
* @param array $params Operation parameters
* @param array $opts Operation options
- * @return Status
+ * @return StatusValue
*/
final public function store( array $params, array $opts = [] ) {
return $this->doOperation( [ 'op' => 'store' ] + $params, $opts );
*
* @param array $params Operation parameters
* @param array $opts Operation options
- * @return Status
+ * @return StatusValue
*/
final public function copy( array $params, array $opts = [] ) {
return $this->doOperation( [ 'op' => 'copy' ] + $params, $opts );
*
* @param array $params Operation parameters
* @param array $opts Operation options
- * @return Status
+ * @return StatusValue
*/
final public function move( array $params, array $opts = [] ) {
return $this->doOperation( [ 'op' => 'move' ] + $params, $opts );
*
* @param array $params Operation parameters
* @param array $opts Operation options
- * @return Status
+ * @return StatusValue
*/
final public function delete( array $params, array $opts = [] ) {
return $this->doOperation( [ 'op' => 'delete' ] + $params, $opts );
*
* @param array $params Operation parameters
* @param array $opts Operation options
- * @return Status
+ * @return StatusValue
* @since 1.21
*/
final public function describe( array $params, array $opts = [] ) {
*
* a) Create a new file in storage with the contents of a string
* @code
- * array(
+ * [
* 'op' => 'create',
* 'dst' => <storage path>,
* 'content' => <string of new file contents>,
* 'headers' => <HTTP header name/value map> # since 1.21
- * )
+ * ]
* @endcode
*
* b) Copy a file system file into storage
* @code
- * array(
+ * [
* 'op' => 'store',
* 'src' => <file system path, FSFile, or TempFSFile>,
* 'dst' => <storage path>,
* 'headers' => <HTTP header name/value map> # since 1.21
- * )
+ * ]
* @endcode
*
* c) Copy a file within storage
* @code
- * array(
+ * [
* 'op' => 'copy',
* 'src' => <storage path>,
* 'dst' => <storage path>,
* 'ignoreMissingSource' => <boolean>, # since 1.21
* 'headers' => <HTTP header name/value map> # since 1.21
- * )
+ * ]
* @endcode
*
* d) Move a file within storage
* @code
- * array(
+ * [
* 'op' => 'move',
* 'src' => <storage path>,
* 'dst' => <storage path>,
* 'ignoreMissingSource' => <boolean>, # since 1.21
* 'headers' => <HTTP header name/value map> # since 1.21
- * )
+ * ]
* @endcode
*
* e) Delete a file within storage
* @code
- * array(
+ * [
* 'op' => 'delete',
* 'src' => <storage path>,
* 'ignoreMissingSource' => <boolean>
- * )
+ * ]
* @endcode
*
* f) Update metadata for a file within storage
* @code
- * array(
+ * [
* 'op' => 'describe',
* 'src' => <storage path>,
* 'headers' => <HTTP header name/value map>
- * )
+ * ]
* @endcode
*
* g) Do nothing (no-op)
* @code
- * array(
+ * [
* 'op' => 'null',
- * )
+ * ]
* @endcode
*
* @par Boolean flags for operations (operation-specific):
* @par Return value:
* This returns a Status, which contains all warnings and fatals that occurred
* during the operation. The 'failCount', 'successCount', and 'success' members
- * will reflect each operation attempted for the given files. The status will be
+ * will reflect each operation attempted for the given files. The StatusValue will be
* considered "OK" as long as no fatal errors occurred.
*
* @param array $ops Set of operations to execute
* @param array $opts Batch operation options
- * @return Status
+ * @return StatusValue
* @since 1.20
*/
final public function doQuickOperations( array $ops, array $opts = [] ) {
if ( empty( $opts['bypassReadOnly'] ) && $this->isReadOnly() ) {
- return Status::newFatal( 'backend-fail-readonly', $this->name, $this->readOnly );
+ return $this->newStatus( 'backend-fail-readonly', $this->name, $this->readOnly );
}
if ( !count( $ops ) ) {
- return Status::newGood(); // nothing to do
+ return $this->newStatus(); // nothing to do
}
$ops = $this->resolveFSFileObjects( $ops );
* @see FileBackend::doQuickOperations()
*
* @param array $op Operation
- * @return Status
+ * @return StatusValue
* @since 1.20
*/
final public function doQuickOperation( array $op ) {
* @see FileBackend::doQuickOperation()
*
* @param array $params Operation parameters
- * @return Status
+ * @return StatusValue
* @since 1.20
*/
final public function quickCreate( array $params ) {
* @see FileBackend::doQuickOperation()
*
* @param array $params Operation parameters
- * @return Status
+ * @return StatusValue
* @since 1.20
*/
final public function quickStore( array $params ) {
* @see FileBackend::doQuickOperation()
*
* @param array $params Operation parameters
- * @return Status
+ * @return StatusValue
* @since 1.20
*/
final public function quickCopy( array $params ) {
* @see FileBackend::doQuickOperation()
*
* @param array $params Operation parameters
- * @return Status
+ * @return StatusValue
* @since 1.20
*/
final public function quickMove( array $params ) {
* @see FileBackend::doQuickOperation()
*
* @param array $params Operation parameters
- * @return Status
+ * @return StatusValue
* @since 1.20
*/
final public function quickDelete( array $params ) {
* @see FileBackend::doQuickOperation()
*
* @param array $params Operation parameters
- * @return Status
+ * @return StatusValue
* @since 1.21
*/
final public function quickDescribe( array $params ) {
* - srcs : ordered source storage paths (e.g. chunk1, chunk2, ...)
* - dst : file system path to 0-byte temp file
* - parallelize : try to do operations in parallel when possible
- * @return Status
+ * @return StatusValue
*/
abstract public function concatenate( array $params );
* - noAccess : try to deny file access (since 1.20)
* - noListing : try to deny file listing (since 1.20)
* - bypassReadOnly : allow writes in read-only mode (since 1.20)
- * @return Status
+ * @return StatusValue
*/
final public function prepare( array $params ) {
if ( empty( $params['bypassReadOnly'] ) && $this->isReadOnly() ) {
- return Status::newFatal( 'backend-fail-readonly', $this->name, $this->readOnly );
+ return $this->newStatus( 'backend-fail-readonly', $this->name, $this->readOnly );
}
/** @noinspection PhpUnusedLocalVariableInspection */
$scope = $this->getScopedPHPBehaviorForOps(); // try to ignore client aborts
* - noAccess : try to deny file access
* - noListing : try to deny file listing
* - bypassReadOnly : allow writes in read-only mode (since 1.20)
- * @return Status
+ * @return StatusValue
*/
final public function secure( array $params ) {
if ( empty( $params['bypassReadOnly'] ) && $this->isReadOnly() ) {
- return Status::newFatal( 'backend-fail-readonly', $this->name, $this->readOnly );
+ return $this->newStatus( 'backend-fail-readonly', $this->name, $this->readOnly );
}
/** @noinspection PhpUnusedLocalVariableInspection */
$scope = $this->getScopedPHPBehaviorForOps(); // try to ignore client aborts
* - access : try to allow file access
* - listing : try to allow file listing
* - bypassReadOnly : allow writes in read-only mode (since 1.20)
- * @return Status
+ * @return StatusValue
* @since 1.20
*/
final public function publish( array $params ) {
if ( empty( $params['bypassReadOnly'] ) && $this->isReadOnly() ) {
- return Status::newFatal( 'backend-fail-readonly', $this->name, $this->readOnly );
+ return $this->newStatus( 'backend-fail-readonly', $this->name, $this->readOnly );
}
/** @noinspection PhpUnusedLocalVariableInspection */
$scope = $this->getScopedPHPBehaviorForOps(); // try to ignore client aborts
* - dir : storage directory
* - recursive : recursively delete empty subdirectories first (since 1.20)
* - bypassReadOnly : allow writes in read-only mode (since 1.20)
- * @return Status
+ * @return StatusValue
*/
final public function clean( array $params ) {
if ( empty( $params['bypassReadOnly'] ) && $this->isReadOnly() ) {
- return Status::newFatal( 'backend-fail-readonly', $this->name, $this->readOnly );
+ return $this->newStatus( 'backend-fail-readonly', $this->name, $this->readOnly );
}
/** @noinspection PhpUnusedLocalVariableInspection */
$scope = $this->getScopedPHPBehaviorForOps(); // try to ignore client aborts
* - headless : only include the body (and headers from "headers") (since 1.28)
* - latest : use the latest available data
* - allowOB : preserve any output buffers (since 1.28)
- * @return Status
+ * @return StatusValue
*/
abstract public function streamFile( array $params );
*
* Write operations should *never* be done on this file as some backends
* may do internal tracking or may be instances of FileBackendMultiWrite.
- * In that later case, there are copies of the file that must stay in sync.
+ * In that latter case, there are copies of the file that must stay in sync.
* Additionally, further calls to this function may return the same file.
*
* @param array $params Parameters include:
* @param array $paths Storage paths
* @param int $type LockManager::LOCK_* constant
* @param int $timeout Timeout in seconds (0 means non-blocking) (since 1.24)
- * @return Status
+ * @return StatusValue
*/
final public function lockFiles( array $paths, $type, $timeout = 0 ) {
$paths = array_map( 'FileBackend::normalizeStoragePath', $paths );
*
* @param array $paths Storage paths
* @param int $type LockManager::LOCK_* constant
- * @return Status
+ * @return StatusValue
*/
final public function unlockFiles( array $paths, $type ) {
$paths = array_map( 'FileBackend::normalizeStoragePath', $paths );
/**
* Lock the files at the given storage paths in the backend.
* This will either lock all the files or none (on failure).
- * On failure, the status object will be updated with errors.
+ * On failure, the StatusValue object will be updated with errors.
*
* Once the return value goes out scope, the locks will be released and
- * the status updated. Unlock fatals will not change the status "OK" value.
+ * the StatusValue updated. Unlock fatals will not change the StatusValue "OK" value.
*
* @see ScopedLock::factory()
*
* @param array $paths List of storage paths or map of lock types to path lists
* @param int|string $type LockManager::LOCK_* constant or "mixed"
- * @param Status $status Status to update on lock/unlock
+ * @param StatusValue $status StatusValue to update on lock/unlock
* @param int $timeout Timeout in seconds (0 means non-blocking) (since 1.24)
* @return ScopedLock|null Returns null on failure
*/
- final public function getScopedFileLocks( array $paths, $type, Status $status, $timeout = 0 ) {
+ final public function getScopedFileLocks(
+ array $paths, $type, StatusValue $status, $timeout = 0
+ ) {
if ( $type === 'mixed' ) {
foreach ( $paths as &$typePaths ) {
$typePaths = array_map( 'FileBackend::normalizeStoragePath', $typePaths );
* @see FileBackend::doOperations()
*
* @param array $ops List of file operations to FileBackend::doOperations()
- * @param Status $status Status to update on lock/unlock
+ * @param StatusValue $status StatusValue to update on lock/unlock
* @return ScopedLock|null
* @since 1.20
*/
- abstract public function getScopedLocksForOps( array $ops, Status $status );
+ abstract public function getScopedLocksForOps( array $ops, StatusValue $status );
/**
* Get the root storage path of this backend.
return $path;
}
+
+ /**
+ * Yields the result of the status wrapper callback on either:
+ * - StatusValue::newGood() if this method is called without parameters
+ * - StatusValue::newFatal() with all parameters to this method if passed in
+ *
+ * @param ... string
+ * @return StatusValue
+ */
+ final protected function newStatus() {
+ $args = func_get_args();
+ if ( count( $args ) ) {
+ $sv = call_user_func_array( [ 'StatusValue', 'newFatal' ], $args );
+ } else {
+ $sv = StatusValue::newGood();
+ }
+
+ return $this->wrapStatus( $sv );
+ }
+
+ /**
+ * @param StatusValue $sv
+ * @return StatusValue Modified status or StatusValue subclass
+ */
+ final protected function wrapStatus( StatusValue $sv ) {
+ return $this->statusWrapper ? call_user_func( $this->statusWrapper, $sv ) : $sv;
+ }
}
/**