diff --git a/.gitignore b/.gitignore
index b3c274d..55de092 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
/vendor
composer.lock
.phpunit*
+/docs/build/
\ No newline at end of file
diff --git a/phpdoc.dist.xml b/phpdoc.dist.xml
new file mode 100644
index 0000000..8e02c39
--- /dev/null
+++ b/phpdoc.dist.xml
@@ -0,0 +1,19 @@
+
+
+
+
+ docs/build/cache
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Classes/AbstractObjectInfo.php b/src/Classes/AbstractObjectInfo.php
index dc0e13a..5886a9d 100644
--- a/src/Classes/AbstractObjectInfo.php
+++ b/src/Classes/AbstractObjectInfo.php
@@ -7,21 +7,15 @@
use function sizeof;
use function rawurlencode;
-//use ArrayAccess;
-//use JsonSerializable;
use RuntimeException;
-//use Zaxbux\BackblazeB2\Traits\ProxyArrayAccessToPropertiesTrait;
-
/**
* @link https://www.backblaze.com/b2/docs/files.html#fileInfo
*
-
+ * @package Zaxbux\BackblazeB2\Classes
*/
abstract class AbstractObjectInfo
{
-//final class FileInfo implements ArrayAccess, JsonSerializable {
- //use ProxyArrayAccessToPropertiesTrait;
public const HEADER_PREFIX = 'X-Bz-Info-';
diff --git a/src/Classes/FilePathInfo.php b/src/Classes/FilePathInfo.php
index c20873f..11cd923 100644
--- a/src/Classes/FilePathInfo.php
+++ b/src/Classes/FilePathInfo.php
@@ -7,6 +7,7 @@
use function pathinfo;
+/** @package Zaxbux\BackblazeB2\Classes */
final class FilePathInfo
{
diff --git a/src/Client.php b/src/Client.php
index 97714cf..87219bb 100644
--- a/src/Client.php
+++ b/src/Client.php
@@ -8,14 +8,23 @@
use GuzzleHttp\Client as GuzzleClient;
use GuzzleHttp\ClientInterface;
use Zaxbux\BackblazeB2\Config;
-use Zaxbux\BackblazeB2\Http\Middleware\ApplyAuthorizationMiddleware;
-use Zaxbux\BackblazeB2\Http\Middleware\ExceptionMiddleware;
-use Zaxbux\BackblazeB2\Http\Middleware\RetryMiddleware;
+use Zaxbux\BackblazeB2\Http\Endpoint;
+use Zaxbux\BackblazeB2\Http\Middleware\{
+ ApplyAuthorizationMiddleware,
+ ExceptionMiddleware,
+ RetryMiddleware,
+};
+use Zaxbux\BackblazeB2\Operations\{
+ ApplicationKeyOperationsTrait,
+ BucketOperationsTrait,
+ DownloadOperationsTrait,
+ FileOperationsTrait,
+ LargeFileOperationsTrait,
+ UploadOperationsTrait,
+};
use Zaxbux\BackblazeB2\Interfaces\AuthorizationCacheInterface;
use Zaxbux\BackblazeB2\Object\AccountAuthorization;
-use Zaxbux\BackblazeB2\Operations\ApplicationKeyOperationsTrait;
-use Zaxbux\BackblazeB2\Operations\BucketOperationsTrait;
-use Zaxbux\BackblazeB2\Operations\FileOperationsTrait;
+use Zaxbux\BackblazeB2\Traits\ApplyToAllFileVersionsTrait;
/**
* API Client for Backblaze B2.
@@ -30,8 +39,12 @@ class Client
public const B2_API_VERSION = 'b2api/v2/';
use FileOperationsTrait;
+ use LargeFileOperationsTrait;
use BucketOperationsTrait;
use ApplicationKeyOperationsTrait;
+ use UploadOperationsTrait;
+ use DownloadOperationsTrait;
+ use ApplyToAllFileVersionsTrait;
/** @var \Zaxbux\BackblazeB2\Config */
protected $config;
@@ -92,7 +105,7 @@ public function __construct($config)
* @param ClientInterface $client
*/
public function authorizeAccount(): AccountAuthorization {
- $response = $this->http->request('GET', Client::BASE_URI . Client::B2_API_VERSION . 'b2_authorize_account', [
+ $response = $this->http->request('GET', Client::BASE_URI . Client::B2_API_VERSION . Endpoint::AUTHORIZE_ACCOUNT, [
'headers' => [
'Authorization' => Utils::basicAuthorization($this->config->applicationKeyId(), $this->config->applicationKey()),
],
@@ -134,7 +147,7 @@ protected function createDefaultHttpClient(): ClientInterface {
}*/
$stack->push(new ExceptionMiddleware(), 'exception_handler');
- $stack->push(new ApplyAuthorizationMiddleware($this), 'b2_auth');
+ $stack->push(new ApplyAuthorizationMiddleware($this), 'b2_authorization');
$stack->push(new RetryMiddleware($this->config), 'retry');
$client = new GuzzleClient([
@@ -143,7 +156,6 @@ protected function createDefaultHttpClient(): ClientInterface {
'allow_redirects' => false,
'handler' => $stack,
'headers' => [
- //'Accept' => 'application/json, */*;q=0.8',
'User-Agent' => Utils::getUserAgent($this->config->applicationName()),
],
]);
@@ -164,7 +176,7 @@ public function getAllowedBucketName(): ?string
/**
* @see __construct()
*/
- public static function instance($config): Client
+ public static function create($config): Client
{
return new static($config);
}
diff --git a/src/Config.php b/src/Config.php
index 12ca625..7f7a1f8 100644
--- a/src/Config.php
+++ b/src/Config.php
@@ -13,6 +13,17 @@
*/
class Config
{
+ public const DEFAULTS = [
+ 'applicationName' => '',
+ 'handler' => null,
+ 'middleware' => [],
+ 'useHttpErrors' => null,
+ 'maxRetries' => 4,
+ 'maxRetryDelay' => 64,
+ 'maxFileCount' => 1000,
+ 'maxKeyCount' => 1000,
+ 'useSSEHeaders' => false,
+ ];
/**
* The identifier for the key. The account ID can also be used.
@@ -30,7 +41,7 @@ class Config
* Application name, included in the User-Agent HTTP header.
* @var string
*/
- private $applicationName = '';
+ private $applicationName;
/**
* Custom Guzzle handler or handler stack.
@@ -48,16 +59,16 @@ class Config
* Optional middleware to add to the GuzzleHttp handler stack.
* @var array
*/
- public $middleware = [];
+ public $middleware;
/** @var bool */
- public $useHttpErrors = false;
+ public $useHttpErrors;
/**
* Number of times to retry an API call before throwing an exception.
* @var int
*/
- public $maxRetries = 4;
+ public $maxRetries;
/**
* Maximum amount of time, in seconds, to wait before retrying a failed request.
@@ -66,31 +77,31 @@ class Config
*
* @var int
*/
- public $maxRetryDelay = 64;
+ public $maxRetryDelay;
/**
* Download files with Server-Side Encryption headers instead of using query parameters.
* @var false
*/
- public $useSSEHeaders = false;
+ public $useSSEHeaders;
/**
* Maximum number of application keys to return per call.
* @var int
*/
- public $maxKeyCount = 1000;
+ public $maxKeyCount;
/**
* Maximum number of files to return per call.
* @var int
*/
- public $maxFileCount = 1000;
+ public $maxFileCount;
/**
* Size limit to determine if the upload will use the large-file process.
* @var int
*/
- public $largeFileUploadCustomMinimum = null; //200 * 1024 * 1024;
+ public $largeFileUploadCustomMinimum; //200 * 1024 * 1024;
/**
* An object that implements `AuthorizationCacheInterface` for caching
@@ -179,8 +190,11 @@ public static function fromArray($data): Config
}
private function setOptions(array $options) {
- $this->handler = $options['handler'] ?? null;
- $this->maxRetries = $options['maxRetries'] ?? 4;
+ $options = array_merge(static::DEFAULTS, $options);
+
+ $this->handler = $options['handler'];
+ $this->maxRetries = $options['maxRetries'];
+ $this->applicationName = $options['applicationName'];
$this->authorizationCache = $options['authorizationCache'] ?? new BuiltinAuthorizationCache();
}
}
\ No newline at end of file
diff --git a/src/Exceptions/NotFoundException.php b/src/Exceptions/NotFoundException.php
index c1b596c..f396e49 100644
--- a/src/Exceptions/NotFoundException.php
+++ b/src/Exceptions/NotFoundException.php
@@ -2,6 +2,7 @@
namespace Zaxbux\BackblazeB2\Exceptions;
+/** @package Zaxbux\BackblazeB2\Exceptions */
class NotFoundException extends \Exception {
}
diff --git a/src/Exceptions/Request/AccessDeniedException.php b/src/Exceptions/Request/AccessDeniedException.php
index 2c9572e..b005760 100644
--- a/src/Exceptions/Request/AccessDeniedException.php
+++ b/src/Exceptions/Request/AccessDeniedException.php
@@ -2,4 +2,5 @@
namespace Zaxbux\BackblazeB2\Exceptions\Request;
+/** @package Zaxbux\BackblazeB2\Exceptions\Request */
class AccessDeniedException extends B2APIException {}
diff --git a/src/Exceptions/Request/B2APIException.php b/src/Exceptions/Request/B2APIException.php
index e84de06..81559e2 100644
--- a/src/Exceptions/Request/B2APIException.php
+++ b/src/Exceptions/Request/B2APIException.php
@@ -8,6 +8,7 @@
use Psr\Http\Message\ResponseInterface;
use Throwable;
+/** @package Zaxbux\BackblazeB2\Exceptions\Request */
class B2APIException extends RequestException {
private $statusCode;
diff --git a/src/Exceptions/Request/BadAuthTokenException.php b/src/Exceptions/Request/BadAuthTokenException.php
index 40fc3fa..804b0d6 100644
--- a/src/Exceptions/Request/BadAuthTokenException.php
+++ b/src/Exceptions/Request/BadAuthTokenException.php
@@ -2,4 +2,5 @@
namespace Zaxbux\BackblazeB2\Exceptions\Request;
+/** @package Zaxbux\BackblazeB2\Exceptions\Request */
class BadAuthTokenException extends B2APIException {}
diff --git a/src/Exceptions/Request/BadRequestException.php b/src/Exceptions/Request/BadRequestException.php
index 8f2d837..65f285e 100644
--- a/src/Exceptions/Request/BadRequestException.php
+++ b/src/Exceptions/Request/BadRequestException.php
@@ -2,4 +2,5 @@
namespace Zaxbux\BackblazeB2\Exceptions\Request;
+/** @package Zaxbux\BackblazeB2\Exceptions\Request */
class BadRequestException extends B2APIException {}
diff --git a/src/Exceptions/Request/CapExceededException.php b/src/Exceptions/Request/CapExceededException.php
index 98d3611..e6d746f 100644
--- a/src/Exceptions/Request/CapExceededException.php
+++ b/src/Exceptions/Request/CapExceededException.php
@@ -2,4 +2,5 @@
namespace Zaxbux\BackblazeB2\Exceptions\Request;
+/** @package Zaxbux\BackblazeB2\Exceptions\Request */
class CapExceededException extends B2APIException {}
diff --git a/src/Exceptions/Request/ConflictException.php b/src/Exceptions/Request/ConflictException.php
index abeeb17..0414b10 100644
--- a/src/Exceptions/Request/ConflictException.php
+++ b/src/Exceptions/Request/ConflictException.php
@@ -2,4 +2,5 @@
namespace Zaxbux\BackblazeB2\Exceptions\Request;
+/** @package Zaxbux\BackblazeB2\Exceptions\Request */
class ConflictException extends B2APIException {}
diff --git a/src/Exceptions/Request/DownloadCapExceededException.php b/src/Exceptions/Request/DownloadCapExceededException.php
index a59742e..a86109c 100644
--- a/src/Exceptions/Request/DownloadCapExceededException.php
+++ b/src/Exceptions/Request/DownloadCapExceededException.php
@@ -2,4 +2,5 @@
namespace Zaxbux\BackblazeB2\Exceptions\Request;
+/** @package Zaxbux\BackblazeB2\Exceptions\Request */
class DownloadCapExceededException extends CapExceededException {}
diff --git a/src/Exceptions/Request/DuplicateBucketNameException.php b/src/Exceptions/Request/DuplicateBucketNameException.php
index 302db86..af0f39e 100644
--- a/src/Exceptions/Request/DuplicateBucketNameException.php
+++ b/src/Exceptions/Request/DuplicateBucketNameException.php
@@ -2,4 +2,5 @@
namespace Zaxbux\BackblazeB2\Exceptions\Request;
+/** @package Zaxbux\BackblazeB2\Exceptions\Request */
class DuplicateBucketNameException extends B2APIException {}
diff --git a/src/Exceptions/Request/ExpiredAuthTokenException.php b/src/Exceptions/Request/ExpiredAuthTokenException.php
index 7e67e67..99479e9 100644
--- a/src/Exceptions/Request/ExpiredAuthTokenException.php
+++ b/src/Exceptions/Request/ExpiredAuthTokenException.php
@@ -2,4 +2,5 @@
namespace Zaxbux\BackblazeB2\Exceptions\Request;
+/** @package Zaxbux\BackblazeB2\Exceptions\Request */
class ExpiredAuthTokenException extends B2APIException {}
diff --git a/src/Exceptions/Request/FileNotPresentException.php b/src/Exceptions/Request/FileNotPresentException.php
index 7d2812d..b142b63 100644
--- a/src/Exceptions/Request/FileNotPresentException.php
+++ b/src/Exceptions/Request/FileNotPresentException.php
@@ -2,4 +2,5 @@
namespace Zaxbux\BackblazeB2\Exceptions\Request;
+/** @package Zaxbux\BackblazeB2\Exceptions\Request */
class FileNotPresentException extends B2APIException {}
diff --git a/src/Exceptions/Request/InvalidBucketIdException.php b/src/Exceptions/Request/InvalidBucketIdException.php
index 80cc347..1b89472 100644
--- a/src/Exceptions/Request/InvalidBucketIdException.php
+++ b/src/Exceptions/Request/InvalidBucketIdException.php
@@ -2,4 +2,5 @@
namespace Zaxbux\BackblazeB2\Exceptions\Request;
+/** @package Zaxbux\BackblazeB2\Exceptions\Request */
class InvalidBucketIdException extends B2APIException {}
diff --git a/src/Exceptions/Request/InvalidFileIdException.php b/src/Exceptions/Request/InvalidFileIdException.php
index fd08bb2..3cc3007 100644
--- a/src/Exceptions/Request/InvalidFileIdException.php
+++ b/src/Exceptions/Request/InvalidFileIdException.php
@@ -2,4 +2,5 @@
namespace Zaxbux\BackblazeB2\Exceptions\Request;
+/** @package Zaxbux\BackblazeB2\Exceptions\Request */
class InvalidFileIdException extends B2APIException {}
diff --git a/src/Exceptions/Request/MethodNotAllowedException.php b/src/Exceptions/Request/MethodNotAllowedException.php
index f1282b8..9e59577 100644
--- a/src/Exceptions/Request/MethodNotAllowedException.php
+++ b/src/Exceptions/Request/MethodNotAllowedException.php
@@ -2,4 +2,5 @@
namespace Zaxbux\BackblazeB2\Exceptions\Request;
+/** @package Zaxbux\BackblazeB2\Exceptions\Request */
class MethodNotAllowedException extends B2APIException {}
diff --git a/src/Exceptions/Request/NotFoundException.php b/src/Exceptions/Request/NotFoundException.php
index 6b3501e..ddd69b8 100644
--- a/src/Exceptions/Request/NotFoundException.php
+++ b/src/Exceptions/Request/NotFoundException.php
@@ -2,4 +2,5 @@
namespace Zaxbux\BackblazeB2\Exceptions\Request;
+/** @package Zaxbux\BackblazeB2\Exceptions\Request */
class NotFoundException extends B2APIException {}
diff --git a/src/Exceptions/Request/OutOfRangeException.php b/src/Exceptions/Request/OutOfRangeException.php
index 6d01571..8365d08 100644
--- a/src/Exceptions/Request/OutOfRangeException.php
+++ b/src/Exceptions/Request/OutOfRangeException.php
@@ -2,4 +2,5 @@
namespace Zaxbux\BackblazeB2\Exceptions\Request;
+/** @package Zaxbux\BackblazeB2\Exceptions\Request */
class OutOfRangeException extends B2APIException {}
diff --git a/src/Exceptions/Request/RangeNotSatisfiableException.php b/src/Exceptions/Request/RangeNotSatisfiableException.php
index b009e51..6ae90ad 100644
--- a/src/Exceptions/Request/RangeNotSatisfiableException.php
+++ b/src/Exceptions/Request/RangeNotSatisfiableException.php
@@ -2,4 +2,5 @@
namespace Zaxbux\BackblazeB2\Exceptions\Request;
+/** @package Zaxbux\BackblazeB2\Exceptions\Request */
class RangeNotSatisfiableException extends B2APIException {}
diff --git a/src/Exceptions/Request/RequestTimeoutException.php b/src/Exceptions/Request/RequestTimeoutException.php
index 6f5d3c0..6adbb47 100644
--- a/src/Exceptions/Request/RequestTimeoutException.php
+++ b/src/Exceptions/Request/RequestTimeoutException.php
@@ -2,4 +2,5 @@
namespace Zaxbux\BackblazeB2\Exceptions\Request;
+/** @package Zaxbux\BackblazeB2\Exceptions\Request */
class RequestTimeoutException extends B2APIException {}
diff --git a/src/Exceptions/Request/ServiceUnavailableException.php b/src/Exceptions/Request/ServiceUnavailableException.php
index e73c557..697da32 100644
--- a/src/Exceptions/Request/ServiceUnavailableException.php
+++ b/src/Exceptions/Request/ServiceUnavailableException.php
@@ -2,4 +2,5 @@
namespace Zaxbux\BackblazeB2\Exceptions\Request;
+/** @package Zaxbux\BackblazeB2\Exceptions\Request */
class ServiceUnavailableException extends B2APIException {}
diff --git a/src/Exceptions/Request/StorageCapExceededException.php b/src/Exceptions/Request/StorageCapExceededException.php
index 9553e05..7722f71 100644
--- a/src/Exceptions/Request/StorageCapExceededException.php
+++ b/src/Exceptions/Request/StorageCapExceededException.php
@@ -2,4 +2,5 @@
namespace Zaxbux\BackblazeB2\Exceptions\Request;
+/** @package Zaxbux\BackblazeB2\Exceptions\Request */
class StorageCapExceededException extends CapExceededException {}
diff --git a/src/Exceptions/Request/TooManyBucketsException.php b/src/Exceptions/Request/TooManyBucketsException.php
index b3b256f..5144b8c 100644
--- a/src/Exceptions/Request/TooManyBucketsException.php
+++ b/src/Exceptions/Request/TooManyBucketsException.php
@@ -2,4 +2,5 @@
namespace Zaxbux\BackblazeB2\Exceptions\Request;
+/** @package Zaxbux\BackblazeB2\Exceptions\Request */
class TooManyBucketsException extends B2APIException {}
diff --git a/src/Exceptions/Request/TransactionCapExceededException.php b/src/Exceptions/Request/TransactionCapExceededException.php
index dc4971e..6b13ce3 100644
--- a/src/Exceptions/Request/TransactionCapExceededException.php
+++ b/src/Exceptions/Request/TransactionCapExceededException.php
@@ -2,4 +2,5 @@
namespace Zaxbux\BackblazeB2\Exceptions\Request;
+/** @package Zaxbux\BackblazeB2\Exceptions\Request */
class TransactionCapExceededException extends CapExceededException {}
diff --git a/src/Exceptions/Request/UnauthorizedException.php b/src/Exceptions/Request/UnauthorizedException.php
index 53cf256..64fa308 100644
--- a/src/Exceptions/Request/UnauthorizedException.php
+++ b/src/Exceptions/Request/UnauthorizedException.php
@@ -2,4 +2,5 @@
namespace Zaxbux\BackblazeB2\Exceptions\Request;
+/** @package Zaxbux\BackblazeB2\Exceptions\Request */
class UnauthorizedException extends B2APIException {}
diff --git a/src/Exceptions/Request/UnsupportedException.php b/src/Exceptions/Request/UnsupportedException.php
index dd0693c..766c9b4 100644
--- a/src/Exceptions/Request/UnsupportedException.php
+++ b/src/Exceptions/Request/UnsupportedException.php
@@ -2,4 +2,5 @@
namespace Zaxbux\BackblazeB2\Exceptions\Request;
+/** @package Zaxbux\BackblazeB2\Exceptions\Request */
class UnsupportedException extends B2APIException {}
diff --git a/src/Helpers/AbstractHelper.php b/src/Helpers/AbstractHelper.php
index 2ecf801..677771e 100644
--- a/src/Helpers/AbstractHelper.php
+++ b/src/Helpers/AbstractHelper.php
@@ -8,6 +8,7 @@
use Zaxbux\BackblazeB2\Client;
use Zaxbux\BackblazeB2\Interfaces\HelperInterface;
+/** @package Zaxbux\BackblazeB2\Helpers */
abstract class AbstractHelper implements HelperInterface
{
/** @var \Zaxbux\BackblazeB2\Client */
diff --git a/src/Helpers/AccountAuthorizationHelper.php b/src/Helpers/AccountAuthorizationHelper.php
deleted file mode 100644
index d184b0d..0000000
--- a/src/Helpers/AccountAuthorizationHelper.php
+++ /dev/null
@@ -1,9 +0,0 @@
- Utils::isStream($sink),
]);
- return FileDownload::create($response, !is_string($sink) ? null : $sink);
+ return FileDownload::fromResponse($response, !is_string($sink) ? null : $sink);
}
}
\ No newline at end of file
diff --git a/src/Helpers/FileBulkOperationsHelper.php b/src/Helpers/FileBulkOperationsHelper.php
new file mode 100644
index 0000000..2be33d6
--- /dev/null
+++ b/src/Helpers/FileBulkOperationsHelper.php
@@ -0,0 +1,79 @@
+fileName = $fileName;
+ return $this;
+ }
+
+ public function list(): Iterator
+ {
+ return $this->client->listAllFileVersions(null, null, null, $this->fileName);
+ }
+
+ public function delete(?bool $bypassGovernance = false): FileList
+ {
+ return $this->client->deleteAllFileVersions(null, $this->fileName, null, null, null, $bypassGovernance);
+ }
+
+ public function updateLegalHold(string $legalHold): FileList
+ {
+ return $this->apply(function(File $version) use ($legalHold) {
+ $this->client->updateFileLegalHold($version->getId(), $version->getName(), $legalHold);
+ });
+ }
+
+ public function updateRetention(array $fileRetention, ?bool $bypassGovernance = false): FileList
+ {
+ return $this->apply(function($version) use ($fileRetention, $bypassGovernance) {
+ $this->client->updateFileRetention(
+ $version->getId(),
+ $version->getName(),
+ $fileRetention,
+ $bypassGovernance
+ );
+ });
+ }
+
+ /**
+ * Applies a callback to each file version.
+ *
+ * @param callable(File):FileList $operation
+ */
+ public function apply(callable $operation): FileList
+ {
+ $fileVersions = $this->list();
+
+ $array = [];
+
+ while ($fileVersions->valid()) {
+ $version = $fileVersions->current();
+
+ $array[] = $operation($version);
+
+ $fileVersions->next();
+ }
+
+ return new FileList(new ArrayIterator($array));
+ }
+}
\ No newline at end of file
diff --git a/src/Helpers/LargeFileUpload.php b/src/Helpers/LargeFileUpload.php
index 85dd508..e78ffb3 100644
--- a/src/Helpers/LargeFileUpload.php
+++ b/src/Helpers/LargeFileUpload.php
@@ -9,7 +9,7 @@
use Zaxbux\BackblazeB2\Object\File\FileUploadMetadata;
use Zaxbux\BackblazeB2\Object\File\ServerSideEncryption;
-
+/** @package Zaxbux\BackblazeB2\Helpers */
class LargeFileUpload {
private $client;
private $stream;
@@ -169,12 +169,12 @@ public function getFile() {
private function minimumPartSize(): int
{
- return $this->accountAuthorization()->getAbsoluteMinimumPartSize();
+ return $this->client->accountAuthorization()->getAbsoluteMinimumPartSize();
}
private function recommendedPartSize(): int
{
- return $this->accountAuthorization()->getRecommendedPartSize();
+ return $this->client->accountAuthorization()->getRecommendedPartSize();
}
private function remainingBytes(): int
diff --git a/src/Helpers/UploadHelper.php b/src/Helpers/UploadHelper.php
index d8d1ab7..f951f99 100644
--- a/src/Helpers/UploadHelper.php
+++ b/src/Helpers/UploadHelper.php
@@ -11,6 +11,7 @@
use Zaxbux\BackblazeB2\Object\File\ServerSideEncryption;
use Zaxbux\BackblazeB2\Object\File\UploadUrl;
+/** @package Zaxbux\BackblazeB2\Helpers */
class UploadHelper extends AbstractHelper {
/**
* Upload a file. Automatically decides the upload method (regular or large file).
diff --git a/tests/Endpoint.php b/src/Http/Endpoint.php
similarity index 95%
rename from tests/Endpoint.php
rename to src/Http/Endpoint.php
index 769d57d..4282c7b 100644
--- a/tests/Endpoint.php
+++ b/src/Http/Endpoint.php
@@ -1,7 +1,8 @@
[
+ StatusCode::HTTP_BAD_REQUEST => [
'bad_request' => BadRequestException::class,
'too_many_buckets' => TooManyBucketsException::class,
'duplicate_bucket_name' => DuplicateBucketNameException::class,
@@ -46,26 +47,26 @@ class ErrorHandler
'bad_bucket_id' => InvalidBucketIdException::class,
'invalid_file_id' => InvalidFileIdException::class,
],
- Response::HTTP_UNAUTHORIZED => [
+ StatusCode::HTTP_UNAUTHORIZED => [
'unsupported' => UnsupportedException::class,
'unauthorized' => UnauthorizedException::class,
'bad_auth_token' => BadAuthTokenException::class,
'expired_auth_token' => ExpiredAuthTokenException::class,
'access_denied' => AccessDeniedException::class,
],
- Response::HTTP_FORBIDDEN => [
+ StatusCode::HTTP_FORBIDDEN => [
'cap_exceeded' => CapExceededException::class,
'storage_cap_exceeded' => StorageCapExceededException::class,
'transaction_cap_exceeded' => TransactionCapExceededException::class,
'access_denied' => AccessDeniedException::class,
'download_cap_exceeded' => DownloadCapExceededException::class,
],
- Response::HTTP_NOT_FOUND => ['not_found' => NotFoundException::class,],
- Response::HTTP_METHOD_NOT_ALLOWED => ['method_not_allowed' => MethodNotAllowedException::class,],
- Response::HTTP_REQUEST_TIMEOUT => ['request_timeout' => RequestTimeoutException::class,],
- Response::HTTP_CONFLICT => ['conflict' => ConflictException::class,],
- Response::HTTP_RANGE_NOT_SATISFIABLE => ['range_not_satisfiable' => RangeNotSatisfiableException::class,],
- Response::HTTP_SERVICE_UNAVAILABLE => [
+ StatusCode::HTTP_NOT_FOUND => ['not_found' => NotFoundException::class,],
+ StatusCode::HTTP_METHOD_NOT_ALLOWED => ['method_not_allowed' => MethodNotAllowedException::class,],
+ StatusCode::HTTP_REQUEST_TIMEOUT => ['request_timeout' => RequestTimeoutException::class,],
+ StatusCode::HTTP_CONFLICT => ['conflict' => ConflictException::class,],
+ StatusCode::HTTP_RANGE_NOT_SATISFIABLE => ['range_not_satisfiable' => RangeNotSatisfiableException::class,],
+ StatusCode::HTTP_SERVICE_UNAVAILABLE => [
'service_unavailable' => ServiceUnavailableException::class,
'bad_request' => BadRequestException::class,
],
diff --git a/src/Http/Exceptions/TooManyRequestsException.php b/src/Http/Exceptions/TooManyRequestsException.php
index 4b1f482..4e3457a 100644
--- a/src/Http/Exceptions/TooManyRequestsException.php
+++ b/src/Http/Exceptions/TooManyRequestsException.php
@@ -2,6 +2,5 @@
namespace Zaxbux\BackblazeB2\Http\Exceptions;
-class TooManyRequestsException extends \GuzzleHttp\Exception\RequestException
-{
-}
+/** @package Zaxbux\BackblazeB2\Http\Exceptions */
+class TooManyRequestsException extends \GuzzleHttp\Exception\RequestException { }
diff --git a/src/Http/Middleware/ApplyAuthorizationMiddleware.php b/src/Http/Middleware/ApplyAuthorizationMiddleware.php
index 9074de7..c470aec 100644
--- a/src/Http/Middleware/ApplyAuthorizationMiddleware.php
+++ b/src/Http/Middleware/ApplyAuthorizationMiddleware.php
@@ -8,6 +8,7 @@
use Zaxbux\BackblazeB2\Client;
use Zaxbux\BackblazeB2\Utils;
+/** @package Zaxbux\BackblazeB2\Http\Middleware */
class ApplyAuthorizationMiddleware
{
private $client;
diff --git a/src/Http/Middleware/ExceptionMiddleware.php b/src/Http/Middleware/ExceptionMiddleware.php
index 4a89482..0a0cfc8 100644
--- a/src/Http/Middleware/ExceptionMiddleware.php
+++ b/src/Http/Middleware/ExceptionMiddleware.php
@@ -6,8 +6,9 @@
use Psr\Http\Message\ResponseInterface;
use Zaxbux\BackblazeB2\Http\ErrorHandler;
use Zaxbux\BackblazeB2\Http\Exceptions\TooManyRequestsException;
-use Zaxbux\BackblazeB2\Http\Response;
+use Zaxbux\BackblazeB2\Http\StatusCode;
+/** @package Zaxbux\BackblazeB2\Http\Middleware */
class ExceptionMiddleware
{
public function __invoke(callable $handler)
@@ -20,7 +21,7 @@ public function __invoke(callable $handler)
return $response;
}
- if ($response->getStatusCode() === Response::HTTP_TOO_MANY_REQUESTS) {
+ if ($response->getStatusCode() === StatusCode::HTTP_TOO_MANY_REQUESTS) {
throw new TooManyRequestsException('', $request, $response);
}
@@ -31,6 +32,6 @@ public function __invoke(callable $handler)
public static function isSuccessful(ResponseInterface $response)
{
- return $response->getStatusCode() >= Response::HTTP_OK && $response->getStatusCode() <= Response::HTTP_PARTIAL_CONTENT;
+ return $response->getStatusCode() >= StatusCode::HTTP_OK && $response->getStatusCode() <= StatusCode::HTTP_PARTIAL_CONTENT;
}
}
diff --git a/src/Http/Middleware/RetryMiddleware.php b/src/Http/Middleware/RetryMiddleware.php
index ee9c629..8429327 100644
--- a/src/Http/Middleware/RetryMiddleware.php
+++ b/src/Http/Middleware/RetryMiddleware.php
@@ -7,13 +7,14 @@
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use Zaxbux\BackblazeB2\Config;
-use Zaxbux\BackblazeB2\Http\Response;
+use Zaxbux\BackblazeB2\Http\StatusCode;
+/** @package Zaxbux\BackblazeB2\Http\Middleware */
class RetryMiddleware
{
protected const RETRY_STATUS_CODES = [
- Response::HTTP_TOO_MANY_REQUESTS,
- Response::HTTP_SERVICE_UNAVAILABLE
+ StatusCode::HTTP_TOO_MANY_REQUESTS,
+ StatusCode::HTTP_SERVICE_UNAVAILABLE
];
/** @var \Zaxbux\BackblazeB2\Config */
@@ -71,7 +72,7 @@ private static function retryDecider(Config $config): callable {
private static function retryDelay(Config $config): callable {
return static function(int $retries, ResponseInterface $response) use ($config): int {
// Use the value of the `Retry-After` header
- if ($response->getStatusCode() === Response::HTTP_TOO_MANY_REQUESTS) {
+ if ($response->getStatusCode() === StatusCode::HTTP_TOO_MANY_REQUESTS) {
$delay = (int) $response->getHeader('Retry-After')[0] ?? $config->maxRetryDelay();
return $delay * 1000;
}
diff --git a/src/Http/Response.php b/src/Http/Response.php
index 1a550fe..0797c29 100644
--- a/src/Http/Response.php
+++ b/src/Http/Response.php
@@ -2,7 +2,8 @@
namespace Zaxbux\BackblazeB2\Http;
-final class Response
+/** @package Zaxbux\BackblazeB2\Http */
+final class StatusCode
{
public const HTTP_CONTINUE = 100;
public const HTTP_SWITCHING_PROTOCOLS = 101;
diff --git a/src/Interfaces/AuthorizationCacheInterface.php b/src/Interfaces/AuthorizationCacheInterface.php
index fe23301..dec613a 100644
--- a/src/Interfaces/AuthorizationCacheInterface.php
+++ b/src/Interfaces/AuthorizationCacheInterface.php
@@ -7,6 +7,7 @@
use Zaxbux\BackblazeB2\Object\AccountAuthorization;
+/** @package Zaxbux\BackblazeB2\Interfaces */
interface AuthorizationCacheInterface
{
diff --git a/src/Interfaces/B2ObjectInterface.php b/src/Interfaces/B2ObjectInterface.php
index 6911b10..ccb3f55 100644
--- a/src/Interfaces/B2ObjectInterface.php
+++ b/src/Interfaces/B2ObjectInterface.php
@@ -7,6 +7,7 @@
use ArrayAccess;
use JsonSerializable;
+/** @package Zaxbux\BackblazeB2\Interfaces */
interface B2ObjectInterface extends JsonSerializable, ArrayAccess
{
public static function fromArray(array $data): B2ObjectInterface;
diff --git a/src/Interfaces/HelperInterface.php b/src/Interfaces/HelperInterface.php
index 349efcb..5140403 100644
--- a/src/Interfaces/HelperInterface.php
+++ b/src/Interfaces/HelperInterface.php
@@ -6,6 +6,7 @@
use Zaxbux\BackblazeB2\Client;
+/** @package Zaxbux\BackblazeB2\Interfaces */
interface HelperInterface
{
public function __construct(Client $client);
diff --git a/src/Object/AccountAuthorization.php b/src/Object/AccountAuthorization.php
index 6655e80..ade0389 100644
--- a/src/Object/AccountAuthorization.php
+++ b/src/Object/AccountAuthorization.php
@@ -5,18 +5,14 @@
namespace Zaxbux\BackblazeB2\Object;
use function time;
-use function json_encode;
-use GuzzleHttp\ClientInterface;
use GuzzleHttp\Utils;
use Psr\Http\Message\ResponseInterface;
-use Zaxbux\BackblazeB2\Client;
-use Zaxbux\BackblazeB2\Config;
use Zaxbux\BackblazeB2\Interfaces\B2ObjectInterface;
use Zaxbux\BackblazeB2\Interfaces\AuthorizationCacheInterface;
use Zaxbux\BackblazeB2\Traits\ProxyArrayAccessToPropertiesTrait;
-
+/** @package Zaxbux\BackblazeB2\Object */
class AccountAuthorization implements B2ObjectInterface
{
use ProxyArrayAccessToPropertiesTrait;
@@ -33,7 +29,7 @@ class AccountAuthorization implements B2ObjectInterface
public const ATTRIBUTE_RECOMMENDED_PART_SIZE = 'recommendedPartSize';
public const ATTRIBUTE_S3_API_URL = 's3ApiUrl';
- /** @deprecated */
+ /** @deprecated Removed in B2 API v2 */
public const ATTRIBUTE_MINIMUM_PART_SIZE = 'minimumPartSize';
/** @var string */
@@ -103,8 +99,10 @@ public function getAuthorizationToken(): ?string
/**
* Get the capabilities, bucket restrictions, and prefix restrictions.
+ *
+ * @return null|string|array
*/
- public function getAllowed(?string $key = null): ?array
+ public function getAllowed(?string $key = null)
{
if ($key) {
return $this->allowed[$key] ?? null;
diff --git a/src/Object/Bucket.php b/src/Object/Bucket.php
index 744d7a7..c02071d 100644
--- a/src/Object/Bucket.php
+++ b/src/Object/Bucket.php
@@ -9,6 +9,7 @@
//use Zaxbux\BackblazeB2\Traits\IterableFromArrayTrait;
use Zaxbux\BackblazeB2\Traits\ProxyArrayAccessToPropertiesTrait;
+/** @package Zaxbux\BackblazeB2\Object */
class Bucket implements B2ObjectInterface
{
use ProxyArrayAccessToPropertiesTrait;
diff --git a/src/Object/Bucket/BucketInfo.php b/src/Object/Bucket/BucketInfo.php
index 8a5f9bb..f22f8fe 100644
--- a/src/Object/Bucket/BucketInfo.php
+++ b/src/Object/Bucket/BucketInfo.php
@@ -9,7 +9,7 @@
/**
* @link https://www.backblaze.com/b2/docs/buckets.html#bucketInfo
*
-
+ * @package Zaxbux\BackblazeB2\Object\Bucket
*/
final class BucketInfo extends AbstractObjectInfo {
public static function fromArray(array $data): BucketInfo {
diff --git a/src/Object/Bucket/BucketType.php b/src/Object/Bucket/BucketType.php
index 289e942..3e87a43 100644
--- a/src/Object/Bucket/BucketType.php
+++ b/src/Object/Bucket/BucketType.php
@@ -4,6 +4,7 @@
namespace Zaxbux\BackblazeB2\Object\Bucket;
+/** @package Zaxbux\BackblazeB2\Object\Bucket */
final class BucketType
{
public const ALL = 'all';
diff --git a/src/Object/Bucket/CORSRule.php b/src/Object/Bucket/CORSRule.php
index c5ffe49..fdba15d 100644
--- a/src/Object/Bucket/CORSRule.php
+++ b/src/Object/Bucket/CORSRule.php
@@ -5,7 +5,9 @@
use JsonSerializable;
/**
- * A CORS rule object for the Backblaze B2 API
+ * A CORS rule object.
+ *
+ * @package Zaxbux\BackblazeB2\Object\Bucket
*/
class CORSRule implements JsonSerializable {
diff --git a/src/Object/Bucket/LifecycleRule.php b/src/Object/Bucket/LifecycleRule.php
index 16b9304..976a671 100644
--- a/src/Object/Bucket/LifecycleRule.php
+++ b/src/Object/Bucket/LifecycleRule.php
@@ -7,7 +7,8 @@
use JsonSerializable;
/**
- * A Lifecycle rule object for the Backblaze B2 API
+ * A Lifecycle rule object.
+ * @package Zaxbux\BackblazeB2\Object\Bucket
*/
class LifecycleRule implements JsonSerializable
{
diff --git a/src/Object/DownloadAuthorization.php b/src/Object/DownloadAuthorization.php
index d46f6d7..6031ff9 100644
--- a/src/Object/DownloadAuthorization.php
+++ b/src/Object/DownloadAuthorization.php
@@ -7,6 +7,7 @@
use Zaxbux\BackblazeB2\Interfaces\B2ObjectInterface;
use Zaxbux\BackblazeB2\Traits\ProxyArrayAccessToPropertiesTrait;
+/** @package Zaxbux\BackblazeB2\Object */
class DownloadAuthorization implements B2ObjectInterface
{
use ProxyArrayAccessToPropertiesTrait;
diff --git a/src/Object/File.php b/src/Object/File.php
index 6c80428..7703835 100644
--- a/src/Object/File.php
+++ b/src/Object/File.php
@@ -12,6 +12,7 @@
use Zaxbux\BackblazeB2\Traits\ProxyArrayAccessToPropertiesTrait;
+/** @package Zaxbux\BackblazeB2\Object */
class File implements B2ObjectInterface
{
use ProxyArrayAccessToPropertiesTrait;
@@ -135,7 +136,7 @@ class File implements B2ObjectInterface
* @param int $uploadTimestamp
* @param string $accountId
* @param array $retention
- * @param array $legalHold
+ * @param string|array $legalHold
* @param array $serverSideEncryption
* @param int $partNumber
*/
@@ -152,7 +153,7 @@ public function __construct(
?int $uploadTimestamp = null,
?string $accountId = null,
?array $retention = null,
- ?array $legalHold = null,
+ $legalHold = null,
?array $serverSideEncryption = null,
?int $partNumber = null
) {
@@ -170,7 +171,7 @@ public function __construct(
$this->uploadTimestamp = $uploadTimestamp;
$this->accountId = $accountId;
$this->retention = $retention;
- $this->legalHold = $legalHold;
+ $this->legalHold = is_array($legalHold) ? $legalHold : ['value' => $legalHold];
$this->serverSideEncryption = $serverSideEncryption instanceof ServerSideEncryption ?
$serverSideEncryption : ServerSideEncryption::fromArray($serverSideEncryption ?? []);
$this->partNumber = $partNumber;
diff --git a/src/Object/File/DownloadOptions.php b/src/Object/File/DownloadOptions.php
index 5adf401..feeb6ea 100644
--- a/src/Object/File/DownloadOptions.php
+++ b/src/Object/File/DownloadOptions.php
@@ -13,6 +13,7 @@
use Zaxbux\BackblazeB2\Object\File\ServerSideEncryption;
use Zaxbux\BackblazeB2\Traits\ProxyArrayAccessToPropertiesTrait;
+/** @package Zaxbux\BackblazeB2\Object\File */
final class DownloadOptions implements ArrayAccess, JsonSerializable
{
use ProxyArrayAccessToPropertiesTrait;
diff --git a/src/Object/File/FileActionType.php b/src/Object/File/FileActionType.php
index b425465..650da89 100644
--- a/src/Object/File/FileActionType.php
+++ b/src/Object/File/FileActionType.php
@@ -6,6 +6,7 @@
use InvalidArgumentException;
+/** @package Zaxbux\BackblazeB2\Object\File */
final class FileActionType
{
/**
diff --git a/src/Object/File/FileInfo.php b/src/Object/File/FileInfo.php
index 47dc11c..de903e4 100644
--- a/src/Object/File/FileInfo.php
+++ b/src/Object/File/FileInfo.php
@@ -10,7 +10,7 @@
/**
* @link https://www.backblaze.com/b2/docs/files.html#fileInfo
*
-
+ * @package Zaxbux\BackblazeB2\Object\File
*/
final class FileInfo extends AbstractObjectInfo {
public const B2_FILE_INFO_MTIME = 'src_last_modified_millis';
diff --git a/src/Object/File/FileLock.php b/src/Object/File/FileLock.php
index 1dac57f..737d934 100644
--- a/src/Object/File/FileLock.php
+++ b/src/Object/File/FileLock.php
@@ -11,7 +11,8 @@
/**
* @link https://www.backblaze.com/b2/docs/server_side_encryption.html
-
+ *
+ * @package Zaxbux\BackblazeB2\Object\File
*/
class FileLock implements JsonSerializable, ArrayAccess {
use ProxyArrayAccessToPropertiesTrait;
diff --git a/src/Object/File/FileUploadMetadata.php b/src/Object/File/FileUploadMetadata.php
index c5023b0..2a43447 100644
--- a/src/Object/File/FileUploadMetadata.php
+++ b/src/Object/File/FileUploadMetadata.php
@@ -10,7 +10,7 @@
/**
* Calculate the length and hash of a string or stream.
*
-
+ * @package Zaxbux\BackblazeB2\Object\File
*/
final class FileUploadMetadata {
diff --git a/src/Object/File/ServerSideEncryption.php b/src/Object/File/ServerSideEncryption.php
index 34ed015..0322624 100644
--- a/src/Object/File/ServerSideEncryption.php
+++ b/src/Object/File/ServerSideEncryption.php
@@ -15,7 +15,7 @@
/**
* @link https://www.backblaze.com/b2/docs/server_side_encryption.html
-
+ * @package Zaxbux\BackblazeB2\Object\File
*/
class ServerSideEncryption implements JsonSerializable, ArrayAccess {
use ProxyArrayAccessToPropertiesTrait;
diff --git a/src/Object/File/UploadPartUrl.php b/src/Object/File/UploadPartUrl.php
index 4a9d53f..cdd0fde 100644
--- a/src/Object/File/UploadPartUrl.php
+++ b/src/Object/File/UploadPartUrl.php
@@ -4,6 +4,7 @@
namespace Zaxbux\BackblazeB2\Object\File;
+/** @package Zaxbux\BackblazeB2\Object\File */
class UploadPartUrl {
public const ATTRIBUTE_FILE_ID = 'fileId';
public const ATTRIBUTE_UPLOAD_URL = 'uploadUrl';
diff --git a/src/Object/File/UploadUrl.php b/src/Object/File/UploadUrl.php
index 7abb553..af54c16 100644
--- a/src/Object/File/UploadUrl.php
+++ b/src/Object/File/UploadUrl.php
@@ -4,6 +4,7 @@
namespace Zaxbux\BackblazeB2\Object\File;
+/** @package Zaxbux\BackblazeB2\Object\File */
class UploadUrl {
public const ATTRIBUTE_BUCKET_ID = 'bucketId';
public const ATTRIBUTE_UPLOAD_URL = 'uploadUrl';
diff --git a/src/Object/Key.php b/src/Object/Key.php
index 9cd4190..7cb3998 100644
--- a/src/Object/Key.php
+++ b/src/Object/Key.php
@@ -7,6 +7,7 @@
use Zaxbux\BackblazeB2\Interfaces\B2ObjectInterface;
use Zaxbux\BackblazeB2\Traits\ProxyArrayAccessToPropertiesTrait;
+/** @package Zaxbux\BackblazeB2\Object */
class Key implements B2ObjectInterface
{
use ProxyArrayAccessToPropertiesTrait;
diff --git a/src/Object/Key/CapabilityType.php b/src/Object/Key/CapabilityType.php
index e577d02..10bb5ea 100644
--- a/src/Object/Key/CapabilityType.php
+++ b/src/Object/Key/CapabilityType.php
@@ -2,6 +2,7 @@
namespace Zaxbux\BackblazeB2\Object\Key;
+/** @package Zaxbux\BackblazeB2\Object\Key */
final class CapabilityType {
public const BYPASS_GOVERNANCE = 'bypassGovernance';
public const DELETE_BUCKETS = 'deleteBuckets';
diff --git a/src/Operations/ApplicationKeyOperationsTrait.php b/src/Operations/ApplicationKeyOperationsTrait.php
index 666a660..d648dc9 100644
--- a/src/Operations/ApplicationKeyOperationsTrait.php
+++ b/src/Operations/ApplicationKeyOperationsTrait.php
@@ -6,11 +6,13 @@
use AppendIterator;
use NoRewindIterator;
+use Zaxbux\BackblazeB2\Http\Endpoint;
use Zaxbux\BackblazeB2\Object\AccountAuthorization;
use Zaxbux\BackblazeB2\Object\Key;
use Zaxbux\BackblazeB2\Response\KeyList;
use Zaxbux\BackblazeB2\Utils;
+/** @package Zaxbux\BackblazeB2\Operations */
trait ApplicationKeyOperationsTrait
{
@@ -24,6 +26,9 @@ abstract protected function accountAuthorization(): AccountAuthorization;
*
* @link https://www.backblaze.com/b2/docs/b2_create_key.html
*
+ * @b2-capability writeKeys
+ * @b2-transaction Class C
+ *
* @param string $keyName A name for this key. There is no requirement that the name be unique.
* The name cannot be used to look up the key.
* @param string[] $capabilities A list of strings, each one naming a capability the new key should have.
@@ -39,7 +44,7 @@ public function createKey(
?string $bucketId = null,
?string $namePrefix = null
): Key {
- $response = $this->http->request('POST', 'b2_create_key', [
+ $response = $this->http->request('POST', Endpoint::CREATE_KEY, [
'json' => Utils::filterRequestOptions([
Key::ATTRIBUTE_ACCOUNT_ID => $this->accountAuthorization()->getAccountId(),
Key::ATTRIBUTE_CAPABILITIES => $capabilities,
@@ -51,25 +56,28 @@ public function createKey(
]),
]);
- return Key::fromArray(json_decode((string) $response->getBody(), true));
+ return Key::fromArray(Utils::jsonDecode($response));
}
/**
* Deletes the application key specified.
*
* @link https://www.backblaze.com/b2/docs/b2_delete_key.html
+ *
+ * @b2-capability deleteKeys
+ * @b2-transaction Class A
*
* @param string $applicationKeyId The key to delete.
*/
public function deleteKey(string $applicationKeyId): Key
{
- $response = $this->http->request('POST', 'b2_delete_key', [
+ $response = $this->http->request('POST', Endpoint::DELETE_KEY, [
'json' => [
Key::ATTRIBUTE_APPLICATION_KEY_ID => $applicationKeyId,
]
]);
- return Key::fromArray(json_decode((string) $response->getBody(), true));
+ return Key::fromArray(Utils::jsonDecode($response));
}
/**
@@ -77,6 +85,9 @@ public function deleteKey(string $applicationKeyId): Key
*
* @link https://www.backblaze.com/b2/docs/b2_list_keys.html
*
+ * @b2-capability listKeys
+ * @b2-transaction Class C
+ *
* @param string $startApplicationKeyId The first key to return.
* @param int $maxKeyCount The maximum number of keys to return in the response. The default value is
* 1000, and the maximum is 10000. The maximum number of keys returned per
@@ -86,7 +97,7 @@ public function listKeys(
?string $startApplicationKeyId = null,
?int $maxKeyCount = 1000
): KeyList {
- $response = $this->http->request('POST', 'b2_list_keys', [
+ $response = $this->http->request('POST', Endpoint::LIST_KEYS, [
'json' => Utils::filterRequestOptions([
Key::ATTRIBUTE_ACCOUNT_ID => $this->accountAuthorization()->getAccountId(),
], [
@@ -95,7 +106,7 @@ public function listKeys(
]),
]);
- return KeyList::create($response);
+ return KeyList::fromResponse($response);
}
/**
diff --git a/src/Operations/BucketOperationsTrait.php b/src/Operations/BucketOperationsTrait.php
index a02b907..1a17f2b 100644
--- a/src/Operations/BucketOperationsTrait.php
+++ b/src/Operations/BucketOperationsTrait.php
@@ -5,6 +5,7 @@
namespace Zaxbux\BackblazeB2\Operations;
use Zaxbux\BackblazeB2\Exceptions\NotFoundException;
+use Zaxbux\BackblazeB2\Http\Endpoint;
use Zaxbux\BackblazeB2\Object\AccountAuthorization;
use Zaxbux\BackblazeB2\Object\Bucket;
use Zaxbux\BackblazeB2\Object\Bucket\BucketInfo;
@@ -12,6 +13,7 @@
use Zaxbux\BackblazeB2\Object\Bucket\BucketType;
use Zaxbux\BackblazeB2\Utils;
+/** @package Zaxbux\BackblazeB2\Operations */
trait BucketOperationsTrait
{
@@ -24,6 +26,9 @@ abstract protected function accountAuthorization(): AccountAuthorization;
* Create a bucket with the given name and type.
*
* @link https://www.backblaze.com/b2/docs/b2_create_bucket.html
+ *
+ * @b2-capability writeBuckets
+ * @b2-transaction Class C
*
* @param string $bucketName The name to give the new bucket.
* @param string $bucketType Either "allPublic", meaning that files in this bucket can be downloaded
@@ -36,11 +41,11 @@ abstract protected function accountAuthorization(): AccountAuthorization;
public function createBucket(
string $bucketName,
?string $bucketType = BucketType::PRIVATE,
- $bucketInfo = null,
+ $bucketInfo = null,
?array $corsRules = null,
?array $lifecycleRules = null
): Bucket {
- $response = $this->http->request('POST', 'b2_create_bucket', [
+ $response = $this->http->request('POST', Endpoint::CREATE_BUCKET, [
'json' => Utils::filterRequestOptions([
Bucket::ATTRIBUTE_ACCOUNT_ID => $this->accountAuthorization()->getAccountId(),
Bucket::ATTRIBUTE_BUCKET_NAME => $bucketName,
@@ -52,13 +57,16 @@ public function createBucket(
]),
]);
- return Bucket::fromArray(json_decode((string) $response->getBody(), true));
+ return Bucket::fromArray(Utils::jsonDecode($response));
}
/**
* Deletes the bucket specified. Only buckets that contain no version of any files can be deleted.
*
- * @link https://www.backblaze.com/b2/docs/b2_delete_bucket.html
+ * @link https://www.backblaze.com/b2/docs/b2_delete_bucket.html
+ *
+ * @b2-capability deleteBuckets
+ * @b2-transaction Class A
*
* @param string $bucketId The ID of the bucket to delete.
* @param bool $withFiles Delete all file versions first.
@@ -70,20 +78,23 @@ public function deleteBucket(string $bucketId, ?bool $withFiles = false): Bucket
$this->deleteAllFileVersions($bucketId);
}
- $response = $this->http->request('POST', 'b2_delete_bucket', [
+ $response = $this->http->request('POST', Endpoint::DELETE_BUCKET, [
'json' => [
Bucket::ATTRIBUTE_ACCOUNT_ID => $this->accountAuthorization()->getAccountId(),
Bucket::ATTRIBUTE_BUCKET_ID => $bucketId
]
]);
- return Bucket::fromArray(json_decode((string) $response->getBody(), true));
+ return Bucket::fromArray(Utils::jsonDecode($response));
}
/**
* Returns a list of bucket objects representing the buckets on the account.
*
* @link https://www.backblaze.com/b2/docs/b2_list_buckets.html
+ *
+ * @b2-capability listBuckets
+ * @b2-transaction Class C
*
* @param string $bucketId When bucketId is specified, the result will be a list containing just this bucket,
* if it's present in the account, or no buckets if the account does not have a
@@ -99,7 +110,7 @@ public function listBuckets(
?string $bucketName = null,
?array $bucketTypes = null
): BucketList {
- $response = $this->http->request('POST', 'b2_list_buckets', [
+ $response = $this->http->request('POST', Endpoint::LIST_BUCKETS, [
'json' => Utils::filterRequestOptions([
Bucket::ATTRIBUTE_ACCOUNT_ID => $this->accountAuthorization()->getAccountId(),
], [
@@ -109,13 +120,16 @@ public function listBuckets(
]),
]);
- return BucketList::create($response);
+ return BucketList::fromResponse($response);
}
/**
* Updates the type attribute of a bucket by the given ID.
*
* @link https://www.backblaze.com/b2/docs/b2_update_bucket.html
+ *
+ * @b2-capability writeBuckets
+ * @b2-transaction Class C
*
* @param string $bucketId The unique ID of the bucket.
* @param string $bucketType Either "allPublic", meaning that files in this bucket can be downloaded
@@ -135,7 +149,7 @@ public function updateBucket(
?array $lifecycleRules = null,
?int $ifRevisionIs = null
): Bucket {
- $response = $this->http->request('POST', 'b2_update_bucket', [
+ $response = $this->http->request('POST', Endpoint::UPDATE_BUCKET, [
'json' => Utils::filterRequestOptions([
Bucket::ATTRIBUTE_ACCOUNT_ID => $this->accountAuthorization()->getAccountId(),
Bucket::ATTRIBUTE_BUCKET_ID => $bucketId ?? $this->getAllowedBucketId(),
@@ -148,7 +162,7 @@ public function updateBucket(
])
]);
- return Bucket::fromArray(json_decode((string) $response->getBody(), true));
+ return Bucket::fromArray(Utils::jsonDecode($response));
}
/**
@@ -165,11 +179,13 @@ public function getBucketById(
): Bucket {
$response = $this->listBuckets($bucketId, null, $bucketTypes);
- if (iterator_count($response->getBuckets()) !== 1) {
+ $buckets = $response->getBucketsArray();
+
+ if (count($buckets) !== 1) {
throw new NotFoundException(sprintf('Bucket "%s" not found.', $bucketId));
}
- return $response->getBuckets()[0];
+ return $buckets[0];
}
/**
@@ -184,10 +200,12 @@ public function getBucketByName(string $bucketName, array $bucketTypes = null):
{
$response = $this->listBuckets(null, $bucketName, $bucketTypes);
- if (iterator_count($response->getBuckets()) !== 1) {
+ $buckets = $response->getBucketsArray();
+
+ if (count($buckets) !== 1) {
throw new NotFoundException(sprintf('Bucket "%s" not found.', $bucketName));
}
- return $response->getBuckets()[0];
+ return $buckets[0];
}
}
diff --git a/src/Operations/DownloadOperationsTrait.php b/src/Operations/DownloadOperationsTrait.php
new file mode 100644
index 0000000..d77fa07
--- /dev/null
+++ b/src/Operations/DownloadOperationsTrait.php
@@ -0,0 +1,125 @@
+http->request('POST', Endpoint::GET_DOWNLOAD_AUTHORIZATION, [
+ 'json' => Utils::filterRequestOptions([
+ File::ATTRIBUTE_BUCKET_ID => $bucketId ?? $this->getAllowedBucketId(),
+ File::ATTRIBUTE_FILE_NAME_PREFIX => $fileNamePrefix,
+ File::ATTRIBUTE_VALID_DURATION => $validDuration,
+ ], $options->getAuthorizationOptions()),
+ ]);
+
+ return DownloadAuthorization::fromArray(Utils::jsonDecode($response));
+ }
+
+ /**
+ * Downloads one file from B2 by File ID.
+ *
+ * @link https://www.backblaze.com/b2/docs/b2_download_file_by_id.html
+ *
+ * @b2-capability [readFiles] If the bucket is private.
+ * @b2-transaction Class B
+ *
+ * @param string $fileId The file ID to download.
+ * @param DownloadOptions|array $options An optional array of additional B2 API options.
+ * @param string $range A standard RFC 7233 byte-range request, that will only return part of the stored file.
+ * @param string|resource $sink A string, stream, or `StreamInterface` that specifies where to save the file.
+ * {@link https://docs.guzzlephp.org/en/stable/request-options.html#sink}
+ * @param bool $headersOnly Only get the file headers, without downloading the whole file.
+ */
+ public function downloadFileById(
+ string $fileId,
+ $options = null,
+ $sink = null,
+ ?bool $headersOnly = false
+ ): FileDownload {
+ return DownloadHelper::instance($this)->download(
+ Utils::joinPaths(
+ $this->accountAuthorization()->getDownloadUrl(),
+ Client::B2_API_VERSION,
+ Endpoint::DOWNLOAD_FILE_BY_ID
+ ),
+ [File::ATTRIBUTE_FILE_ID => $fileId],
+ $options,
+ $sink,
+ $headersOnly
+ );
+ }
+
+ /**
+ * Downloads one file from B2 by File Name.
+ *
+ * @b2-capability [readFiles] If the bucket is private.
+ * @b2-transaction Class B
+ *
+ * @link https://www.backblaze.com/b2/docs/b2_download_file_by_name.html
+ *
+ * @param string $fileName The file name to download.
+ * @param string $bucketName The bucket the file is contained in.
+ * @param DownloadOptions|array $options An optional array of additional B2 API options.
+ * @param string $range A standard RFC 7233 byte-range request, that will only return part of the stored file.
+ * @param string|resource $sink A string, stream, or `StreamInterface` that specifies where to save the file.
+ * {@link https://docs.guzzlephp.org/en/stable/request-options.html#sink}
+ * @param bool $headersOnly Only get the file headers, without downloading the whole file.
+ */
+ public function downloadFileByName(
+ string $fileName,
+ ?string $bucketName = null,
+ $options = null,
+ $sink = null,
+ ?bool $headersOnly = false
+ ): FileDownload {
+ return DownloadHelper::instance($this)->download(
+ Utils::joinPaths(
+ $this->accountAuthorization()->getApiUrl(),
+ 'file',
+ $bucketName ?? $this->getAllowedBucketName(),
+ $fileName
+ ),
+ null,
+ $options,
+ $sink,
+ $headersOnly
+ );
+ }
+}
\ No newline at end of file
diff --git a/src/Operations/FileOperationsTrait.php b/src/Operations/FileOperationsTrait.php
index c2fc06b..b586123 100644
--- a/src/Operations/FileOperationsTrait.php
+++ b/src/Operations/FileOperationsTrait.php
@@ -8,23 +8,15 @@
use ArrayIterator;
use Iterator;
use NoRewindIterator;
-use Zaxbux\BackblazeB2\Client;
use Zaxbux\BackblazeB2\Exceptions\NotFoundException;
-use Zaxbux\BackblazeB2\Helpers\DownloadHelper;
+use Zaxbux\BackblazeB2\Http\Endpoint;
use Zaxbux\BackblazeB2\Object\AccountAuthorization;
use Zaxbux\BackblazeB2\Object\File;
-use Zaxbux\BackblazeB2\Object\DownloadAuthorization;
-use Zaxbux\BackblazeB2\Object\File\DownloadOptions;
-use Zaxbux\BackblazeB2\Object\File\FileUploadMetadata;
-use Zaxbux\BackblazeB2\Object\File\FileInfo;
use Zaxbux\BackblazeB2\Object\File\ServerSideEncryption;
-use Zaxbux\BackblazeB2\Object\File\UploadPartUrl;
-use Zaxbux\BackblazeB2\Object\File\UploadUrl;
-use Zaxbux\BackblazeB2\Response\FileDownload;
use Zaxbux\BackblazeB2\Response\FileList;
-use Zaxbux\BackblazeB2\Response\FilePartList;
use Zaxbux\BackblazeB2\Utils;
+/** @package Zaxbux\BackblazeB2\Operations */
trait FileOperationsTrait
{
@@ -33,29 +25,15 @@ trait FileOperationsTrait
abstract protected function accountAuthorization(): AccountAuthorization;
- /**
- * Cancel the upload of a large file, and deletes all of the parts that have been uploaded.
- *
- * @link https://www.backblaze.com/b2/docs/b2_cancel_large_file.html
- *
- * @param string $fileId The ID returned by `b2_start_large_file`.
- */
- public function cancelLargeFile(string $fileId)
- {
- $response = $this->http->request('POST', 'b2_cancel_large_file', [
- 'json' => [
- File::ATTRIBUTE_FILE_ID => $fileId,
- ],
- ]);
-
- return File::fromArray(json_decode((string) $response->getBody(), true));
- }
-
/**
* Creates a new file by copying from an existing file.
*
* @link https://www.backblaze.com/b2/docs/b2_copy_file.html
*
+ * @b2-capability writeFiles
+ * @b2-capability [readFiles] If the bucket is private.
+ * @b2-transaction Class C
+ *
* @param string $sourceFileId The ID of the source file being copied.
* @param string $fileName The name of the new file being created.
* @param string $destinationBucketId The ID of the bucket where the copied file will be stored.
@@ -84,34 +62,7 @@ public function copyFile(
?ServerSideEncryption $sourceSSE = null,
?ServerSideEncryption $destinationSSE = null
): File {
-
- /*
- if ($metadataDirective) {
- if ($metadataDirective == File::METADATA_DIRECTIVE_REPLACE && $contentType == null) {
- $contentType = File::CONTENT_TYPE_AUTO;
- }
-
- if ($contentType && $metadataDirective !== File::METADATA_DIRECTIVE_REPLACE) {
- throw new InvalidArgumentException(sprintf(
- '%s must not be set when %s is not "%s".',
- File::ATTRIBUTE_CONTENT_TYPE,
- File::ATTRIBUTE_METADATA_DIRECTIVE,
- File::METADATA_DIRECTIVE_REPLACE
- ));
- }
-
- if ($fileInfo && $metadataDirective !== File::METADATA_DIRECTIVE_REPLACE) {
- throw new InvalidArgumentException(sprintf(
- '%s must not be set when %s is not "%s".',
- File::ATTRIBUTE_FILE_INFO,
- File::ATTRIBUTE_METADATA_DIRECTIVE,
- File::METADATA_DIRECTIVE_REPLACE
- ));
- }
- }
- */
-
- $response = $this->http->request('POST', 'b2_copy_file', [
+ $response = $this->http->request('POST', Endpoint::COPY_FILE, [
'json' => Utils::filterRequestOptions([
File::ATTRIBUTE_SOURCE_FILE_ID => $sourceFileId,
File::ATTRIBUTE_FILE_NAME => $fileName,
@@ -128,247 +79,58 @@ public function copyFile(
])
]);
- return File::fromArray(json_decode((string) $response->getBody(), true));
- }
-
- /**
- * Copies from an existing B2 file, storing it as a part of a large file which has already been started with
- * `b2_start_large_file`.
- *
- * @link https://www.backblaze.com/b2/docs/b2_copy_part.html
- *
- * @param string $sourceFileId The ID of the source file being copied.
- * @param string $largeFileId The ID of the large file the part will belong to.
- * @param int $partNumber A number from `1` to `10000`. The parts uploaded for one file must have
- * contiguous numbers, starting with `1`.
- * @param string $range The range of bytes to copy.
- * If not provided, the whole source file will be copied.
- * @param array $sourceSSE Specifies the parameters for B2 to use for accessing the
- * source file data using Server-Side Encryption.
- * @param array $destinationSSE Specifies the parameters for B2 to use for encrypting the
- * copied data before storing the destination file using Server-Side Encryption.
- */
- public function copyPart(
- string $sourceFileId,
- string $largeFileId,
- int $partNumber,
- ?string $range = null,
- ?ServerSideEncryption $sourceSSE = null,
- ?ServerSideEncryption $destinationSSE = null
- ): File {
- $response = $this->http->request('POST', 'b2_copy_part', [
- 'json' => Utils::filterRequestOptions([
- File::ATTRIBUTE_SOURCE_FILE_ID => $sourceFileId,
- File::ATTRIBUTE_LARGE_FILE_ID => $largeFileId,
- File::ATTRIBUTE_PART_NUMBER => $partNumber,
- ], [
- File::ATTRIBUTE_RANGE => $range,
- File::ATTRIBUTE_SOURCE_SSE => $sourceSSE,
- File::ATTRIBUTE_DESTINATION_SSE => $destinationSSE,
- ]),
- ]);
-
- return File::fromArray(json_decode((string) $response->getBody(), true));
+ return File::fromArray(Utils::jsonDecode($response));
}
/**
* Deletes one version of a file.
*
* @link https://www.backblaze.com/b2/docs/b2_delete_file_version.html
+ *
+ * @b2-capability deleteFiles
+ * @b2-transaction Class A
*
* @param string $fileName The name of the file.
* @param string $fileId The ID of the file.
* @param bool $bypassGovernance Must be specified and set to true if deleting a file version protected by
* File Lock governance mode retention settings.
*/
- public function deleteFileVersion(string $fileId, string $fileName, ?bool $bypassGovernance = false): File
- {
- $response = $this->http->request('POST', 'b2_delete_file_version', [
+ public function deleteFileVersion(
+ string $fileId,
+ ?string $fileName = null,
+ ?bool $bypassGovernance = false
+ ): File {
+ $response = $this->http->request('POST', Endpoint::DELETE_FILE_VERSION, [
'json' => Utils::filterRequestOptions([
- File::ATTRIBUTE_FILE_NAME => $fileName,
File::ATTRIBUTE_FILE_ID => $fileId,
+ File::ATTRIBUTE_FILE_NAME => $fileName ?? $this->getFileById($fileId)->getId(),
], [
File::ATTRIBUTE_BYPASS_GOVERNANCE => $bypassGovernance,
]),
]);
- return File::fromArray(json_decode((string) $response->getBody(), true));
- }
-
- /**
- * Downloads one file from B2 by File ID.
- *
- * @link https://www.backblaze.com/b2/docs/b2_download_file_by_id.html
- *
- * @param string $fileId The file ID to download.
- * @param DownloadOptions|array $options An optional array of additional B2 API options.
- * @param string $range A standard RFC 7233 byte-range request, that will only return part of the stored file.
- * @param string|resource $sink A string, stream, or `StreamInterface` that specifies where to save the file.
- * {@link https://docs.guzzlephp.org/en/stable/request-options.html#sink}
- * @param bool $headersOnly Only get the file headers, without downloading the whole file.
- */
- public function downloadFileById(
- string $fileId,
- $options = null,
- $sink = null,
- ?bool $headersOnly = false
- ): FileDownload {
- return DownloadHelper::instance($this)->download(
- Utils::joinPaths(
- $this->accountAuthorization()->getDownloadUrl(),
- Client::B2_API_VERSION,
- 'b2_download_file_by_id'
- ),
- [File::ATTRIBUTE_FILE_ID => $fileId],
- $options,
- $sink,
- $headersOnly
- );
- }
-
- /**
- * Downloads one file from B2 by File Name.
- *
- * @link https://www.backblaze.com/b2/docs/b2_download_file_by_name.html
- *
- * @param string $fileName The file name to download.
- * @param string $bucketName The bucket the file is contained in.
- * @param DownloadOptions|array $options An optional array of additional B2 API options.
- * @param string $range A standard RFC 7233 byte-range request, that will only return part of the stored file.
- * @param string|resource $sink A string, stream, or `StreamInterface` that specifies where to save the file.
- * {@link https://docs.guzzlephp.org/en/stable/request-options.html#sink}
- * @param bool $headersOnly Only get the file headers, without downloading the whole file.
- */
- public function downloadFileByName(
- string $fileName,
- ?string $bucketName = null,
- $options = null,
- $sink = null,
- ?bool $headersOnly = false
- ): FileDownload {
- return DownloadHelper::instance($this)->download(
- Utils::joinPaths(
- $this->accountAuthorization()->getApiUrl(),
- 'file',
- $bucketName ?? $this->getAllowedBucketName(),
- $fileName
- ),
- null,
- $options,
- $sink,
- $headersOnly
- );
- }
-
- /**
- * Converts the parts that have been uploaded into a single B2 file.
- *
- * @link https://www.backblaze.com/b2/docs/b2_finish_large_file.html
- *
- * @param string $fileId The ID of the large file.
- * @param string[] $hashes An array of SHA1 checksums of the parts of the large file.
- *
- * @return File
- */
- public function finishLargeFile(string $fileId, array $hashes)
- {
- $response = $this->http->request('POST', 'b2_finish_large_file', [
- 'json' => [
- File::ATTRIBUTE_FILE_ID => $fileId,
- File::ATTRIBUTE_PART_SHA1_ARRAY => $hashes,
- ]
- ]);
-
- return File::fromArray(json_decode((string) $response->getBody(), true));
- }
-
- /**
- * Generates an authorization token that can be used to download files
- * with the specified prefix from a private B2 bucket.
- *
- * @link https://www.backblaze.com/b2/docs/b2_get_download_authorization.html
- *
- * @param string $bucketId The identifier for the bucket.
- * @param string $fileNamePrefix The file name prefix of files the download authorization token will allow access.
- * @param int $validDuration The number of seconds before the authorization token will expire. The minimum
- * value is `1` second. The maximum value is `604800`. Default: `604800`.
- * @param DownloadOptions|array $options Additional options to pass to the API.
- */
- public function getDownloadAuthorization(
- string $fileNamePrefix,
- ?string $bucketId = null,
- ?int $validDuration = DownloadAuthorization::VALID_DURATION_MAX,
- $options = null
- ): DownloadAuthorization {
- if (!$options instanceof DownloadOptions) {
- $options = DownloadOptions::fromArray($options ?? []);
- }
-
- $response = $this->http->request('POST', 'b2_get_download_authorization', [
- 'json' => Utils::filterRequestOptions([
- File::ATTRIBUTE_BUCKET_ID => $bucketId ?? $this->getAllowedBucketId(),
- File::ATTRIBUTE_FILE_NAME_PREFIX => $fileNamePrefix,
- File::ATTRIBUTE_VALID_DURATION => $validDuration,
- ], $options->getAuthorizationOptions()),
- ]);
-
- return DownloadAuthorization::fromArray(json_decode((string) $response->getBody(), true));
+ return File::fromArray(Utils::jsonDecode($response));
}
/**
* Gets information about one file stored in B2.
*
* @link https://www.backblaze.com/b2/docs/b2_get_file_info.html
+ *
+ * @b2-capability readFiles
+ * @b2-transaction Class B
*
* @param string $fileId The ID of the file.
*/
public function getFileInfo(string $fileId): File
{
- $response = $this->http->request('POST', 'b2_get_file_info', [
+ $response = $this->http->request('POST', Endpoint::GET_FILE_INFO, [
'json' => [
File::ATTRIBUTE_FILE_ID => $fileId
]
]);
- return File::fromArray(json_decode((string) $response->getBody(), true));
- }
-
- /**
- * Gets a URL to use for uploading parts of a large file.
- *
- * @link https://www.backblaze.com/b2/docs/b2_get_upload_part_url.html
- *
- * @param string $fileId The ID of the large file to upload parts of.
- */
- public function getUploadPartUrl(string $fileId): UploadPartUrl
- {
- $response = $this->http->request('POST', 'b2_get_upload_part_url', [
- 'json' => [
- File::ATTRIBUTE_FILE_ID => $fileId
- ]
- ]);
-
- return UploadPartUrl::fromArray(json_decode((string) $response->getBody(), true));
- }
-
- /**
- * Gets a URL and authorization token to use for uploading files.
- *
- * @link https://www.backblaze.com/b2/docs/b2_get_upload_url.html
- *
- * @param string $bucketId The ID of the bucket to upload files to.
- *
- * @return UploadUrl
- */
- public function getUploadUrl(?string $bucketId): UploadUrl
- {
- $response = $this->http->request('POST', 'b2_get_upload_url', [
- 'json' => [
- File::ATTRIBUTE_BUCKET_ID => $bucketId ?? $this->getAllowedBucketId()
- ]
- ]);
-
- return UploadUrl::fromArray(json_decode((string) $response->getBody(), true));
+ return File::fromArray(Utils::jsonDecode($response));
}
/**
@@ -377,26 +139,32 @@ public function getUploadUrl(?string $bucketId): UploadUrl
*
* @link https://www.backblaze.com/b2/docs/b2_hide_file.html
*
+ * @b2-capability writeFiles
+ * @b2-transaction Class A
+ *
* @param string $bucketId
* @param string $fileName
*/
public function hideFile(string $fileName, ?string $bucketId = null): File
{
- $response = $this->http->request('POST', 'b2_hide_file', [
+ $response = $this->http->request('POST', Endpoint::HIDE_FILE, [
'json' => [
File::ATTRIBUTE_BUCKET_ID => $bucketId ?? $this->getAllowedBucketId(),
File::ATTRIBUTE_FILE_NAME => $fileName,
]
]);
- return File::fromArray(json_decode((string) $response->getBody(), true));
+ return File::fromArray(Utils::jsonDecode($response));
}
/**
* Lists the names of all files in a bucket, starting at a given name.
*
* @link https://www.backblaze.com/b2/docs/b2_list_file_names.html
+ *
+ * @b2-capability listFiles
+ * @b2-transaction Class C
*
* @param string $bucketId The bucket to look for file names in.
* @param string $prefix Files returned will be limited to those with the given prefix. Defaults to the
@@ -417,7 +185,7 @@ public function listFileNames(
?string $startFileName = null,
?int $maxFileCount = 1000
): FileList {
- $response = $this->http->request('POST', 'b2_list_file_names', [
+ $response = $this->http->request('POST', Endpoint::LIST_FILE_NAMES, [
'json' => Utils::filterRequestOptions([
File::ATTRIBUTE_BUCKET_ID => $bucketId ?? $this->getAllowedBucketId(),
File::ATTRIBUTE_MAX_FILE_COUNT => $maxFileCount,
@@ -428,7 +196,7 @@ public function listFileNames(
]),
]);
- return FileList::create($response);
+ return FileList::fromResponse($response);
}
/**
@@ -437,6 +205,9 @@ public function listFileNames(
*
* @link https://www.backblaze.com/b2/docs/b2_list_file_versions.html
*
+ * @b2-capability listFiles
+ * @b2-transaction Class C
+ *
* @param string $bucketId The bucket to look for file names in.
* @param string $prefix Files returned will be limited to those with the given prefix. Defaults to the
* empty string, which matches all files. If not, the first file name after this the
@@ -459,7 +230,7 @@ public function listFileVersions(
?string $startFileId = null,
?int $maxFileCount = 1000
): FileList {
- $response = $this->http->request('POST', 'b2_list_file_versions', [
+ $response = $this->http->request('POST', Endpoint::LIST_FILE_VERSIONS, [
'json' => Utils::filterRequestOptions([
File::ATTRIBUTE_BUCKET_ID => $bucketId ?? $this->getAllowedBucketId(),
], [
@@ -471,109 +242,7 @@ public function listFileVersions(
]),
]);
- return FileList::create($response);
- }
-
- /**
- * Lists the parts that have been uploaded for a large file that has not been finished yet.
- *
- * @link https://www.backblaze.com/b2/docs/b2_list_parts.html
- *
- * @param string $fileId The ID returned by b2_start_large_file. This is the file whose parts will be
- * listed.
- * @param int $startPartNumber The first part to return. Used when a query hits the maxKeyCount, and you want to
- * get more.
- * @param int $maxPartCount The maximum number of parts to return in the response. The default value is 1000,
- * and the maximum is 10000. The maximum number of parts returned per transaction
- * is 1000.
- * If more than 1000 are returned, the call will be billed as multiple transactions.
- * @param bool $loop Make API requests until there are no keys left.
- */
- public function listParts(
- string $fileId,
- ?int $startPartNumber = null,
- ?int $maxPartCount = 1000
- ): FilePartList {
- $response = $this->http->request('POST', 'b2_list_parts', [
- 'json' => Utils::filterRequestOptions([
- File::ATTRIBUTE_FILE_ID => $fileId
- ], [
- File::ATTRIBUTE_START_PART_NUMBER => $startPartNumber,
- File::ATTRIBUTE_MAX_PART_COUNT => $maxPartCount,
- ]),
- ]);
-
- return FilePartList::create($response);
- }
-
- /**
- * Lists information about large file uploads that have been started,
- * but that have not been finished or canceled.
- *
- * @link https://www.backblaze.com/b2/docs/b2_list_unfinished_large_files.html
- *
- * @param string $bucketId The bucket to look for file names in.
- * @param string $namePrefix Only return files whose names match this prefix.
- * @param string $startFileId The first upload to return.
- * @param int $maxFileCount The maximum number of files to return from this call. The default value is 100, and
- * the maximum allowed is 100.
- */
- public function listUnfinishedLargeFiles(
- ?string $bucketId = null,
- ?string $namePrefix = null,
- ?string $startFileId = null,
- ?int $maxFileCount = 100
- ): FileList {
- $response = $this->http->request('POST', 'b2_list_unfinished_large_files', [
- 'json' => Utils::filterRequestOptions([
- File::ATTRIBUTE_BUCKET_ID => $bucketId ?? $this->getAllowedBucketId(),
- ], [
- File::ATTRIBUTE_NAME_PREFIX => $namePrefix,
- File::ATTRIBUTE_START_FILE_ID => $startFileId,
- File::ATTRIBUTE_MAX_FILE_COUNT => $maxFileCount,
- ]),
- ]);
-
- return FileList::create($response);
- }
-
- /**
- * Prepares for uploading the parts of a large file.
- *
- * @link https://www.backblaze.com/b2/docs/b2_start_large_file.html
- *
- * @param string $bucketId The ID of the bucket that the file will go in.
- * @param string $fileName The name of the file.
- * @param string $contentType The MIME type of the content of the file.
- * @param FileInfo|array $fileInfo A JSON object holding the name/value pairs for the custom file info.
- */
- public function startLargeFile(
- string $fileName,
- ?string $bucketId = null,
- ?string $contentType = null,
- $fileInfo = null,
- ?array $fileRetention = null,
- ?array $legalHold = null,
- ?array $serverSideEncryption = null
- ): File {
- if (!$fileInfo instanceof FileInfo) {
- $fileInfo = FileInfo::fromArray($fileInfo);
- }
-
- $response = $this->http->request('POST', 'b2_start_large_file', [
- 'json' => Utils::filterRequestOptions([
- File::ATTRIBUTE_BUCKET_ID => $bucketId ?? $this->getAllowedBucketId(),
- File::ATTRIBUTE_FILE_NAME => $fileName,
- File::ATTRIBUTE_CONTENT_TYPE => $contentType ?? File::CONTENT_TYPE_AUTO,
- ], [
- File::ATTRIBUTE_FILE_INFO => $fileInfo->get(),
- File::ATTRIBUTE_FILE_RETENTION => $fileRetention,
- File::ATTRIBUTE_LEGAL_HOLD => $legalHold,
- File::ATTRIBUTE_SSE => $serverSideEncryption,
- ])
- ]);
-
- return File::fromArray(json_decode((string) $response->getBody(), true));
+ return FileList::fromResponse($response);
}
/**
@@ -581,24 +250,27 @@ public function startLargeFile(
*
* @link https://www.backblaze.com/b2/docs/b2_update_file_legal_hold.html
*
+ * @b2-capability writeFileLegalHolds
+ * @b2-transaction Class A
+ *
* @param string $fileName The name of the file.
* @param string $fileId The ID of the file.
* @param string $legalHold The legal hold status of the file. `on` = *enabled*; `off` = *disabled*.
*/
public function updateFileLegalHold(
- string $fileName,
string $fileId,
+ ?string $fileName = null,
string $legalHold
): File {
- $response = $this->http->request('POST', 'b2_update_file_legal_hold', [
+ $response = $this->http->request('POST', Endpoint::UPDATE_FILE_LEGAL_HOLD, [
'json' => Utils::filterRequestOptions([
- File::ATTRIBUTE_FILE_NAME => $fileName,
+ File::ATTRIBUTE_FILE_NAME => $fileName ?? $this->getFileById($fileId)->getId(),
File::ATTRIBUTE_FILE_ID => $fileId,
File::ATTRIBUTE_LEGAL_HOLD => $legalHold,
]),
]);
- return File::fromArray(json_decode((string) $response->getBody(), true));
+ return File::fromArray(Utils::jsonDecode($response));
}
/**
@@ -606,126 +278,31 @@ public function updateFileLegalHold(
*
* @link https://www.backblaze.com/b2/docs/b2_update_file_retention.html
*
+ * @b2-capability writeFileRetentions
+ * @b2-transaction Class A
+ *
* @param string $fileName The name of the file.
* @param string $fileId The ID of the file.
- * @param string $fileRetention The legal hold status of the file. `on` = *enabled*; `off` = *disabled*.
+ * @param array $fileRetention The file retention settings.
* @param bool $bypassGovernance To shorten or remove an existing governance mode retention setting,
* this must also be specified and set to `true`.
*/
public function updateFileRetention(
- string $fileName,
string $fileId,
- string $fileRetention,
+ ?string $fileName = null,
+ array $fileRetention,
?bool $bypassGovernance = false
): File {
- $response = $this->http->request('POST', 'b2_update_file_retention', [
+ $response = $this->http->request('POST', Endpoint::UPDATE_FILE_RETENTION, [
'json' => Utils::filterRequestOptions([
- File::ATTRIBUTE_FILE_NAME => $fileName,
+ File::ATTRIBUTE_FILE_NAME => $fileName ?? $this->getFileById($fileId)->getId(),
File::ATTRIBUTE_FILE_ID => $fileId,
File::ATTRIBUTE_FILE_RETENTION => $fileRetention,
File::ATTRIBUTE_BYPASS_GOVERNANCE => $bypassGovernance,
]),
]);
- return File::fromArray(json_decode((string) $response->getBody(), true));
- }
-
- /**
- * Uploads a file to a bucket and returns the uploaded file as an object.
- *
- * @link https://www.backblaze.com/b2/docs/b2_upload_file.html
- *
- * @param string $bucketId The ID of the bucket to upload the file to.
- * @param string $fileName The name of the file.
- * @param string|resource $body The file to be uploaded. String or stream resource.
- * @param string $contentType The MIME type of the content of the file.
- * @param FileInfo|array $fileInfo The custom file info to add to the uploaded file.
- * @param ServerSideEncryption|array $serverSideEncryption The parameters for B2 to encrypt the uploaded file.
- * @param UploadUrl $uploadUrl The upload authorization data.
- */
- public function uploadFile(
- string $fileName,
- ?string $bucketId = null,
- $body,
- ?string $contentType = null,
- $fileInfo = null,
- $serverSideEncryption = null,
- ?UploadUrl $uploadUrl = null
- ): File {
- if (!$fileInfo instanceof FileInfo) {
- $fileInfo = FileInfo::fromArray($fileInfo ?? []);
- }
-
- if (!$serverSideEncryption instanceof ServerSideEncryption) {
- $serverSideEncryption = ServerSideEncryption::fromArray($serverSideEncryption ?? []);
- }
-
- if (!$uploadUrl instanceof UploadUrl) {
- $uploadUrl = $this->getUploadUrl($bucketId);
- }
-
- $uploadMetadata = FileUploadMetadata::fromResource($body);
- $mtime = $uploadMetadata->getLastModifiedTimestamp();
- if ($mtime > 0) {
- $fileInfo->setLastModifiedTimestamp($mtime);
- }
-
- $response = $this->http->request('POST', $uploadUrl->getUploadUrl(), [
- 'body' => $body,
- 'headers' => Utils::filterRequestOptions(
- [
- 'Authorization' => $uploadUrl->getAuthorizationToken(),
- 'Content-Type' => $contentType ?? File::CONTENT_TYPE_AUTO,
- 'Content-Length' => $uploadMetadata->getLength(),
- File::HEADER_X_BZ_CONTENT_SHA1 => $uploadMetadata->getSha1(),
- File::HEADER_X_BZ_FILE_NAME => $fileName, //rawurlencode($fileName),// urlencode($fileName),
- ],
- ($serverSideEncryption->getHeaders() ?? []),
- ($fileInfo->getHeaders() ?? [])
- ),
- ]);
-
- return File::fromArray(json_decode((string) $response->getBody(), true));
- }
-
- /**
- * Uploads one part of a large file.
- *
- * @link https://www.backblaze.com/b2/docs/b2_upload_part.html
- *
- * @param string|resource $body The file part to be uploaded. String or stream resource.
- * @param string $fileId The ID of the large file whose parts you want to upload.
- * @param int $partNumber The parts uploaded for one file must have contiguous numbers, starting with 1.
- * @param ServerSideEncryption|array $serverSideEncryption The parameters for B2 to encrypt the uploaded file.
- * @param UploadPartUrl $uploadPartUrl The upload part authorization data.
- */
- public function uploadPart(
- $body,
- string $fileId,
- ?int $partNumber = 1,
- $serverSideEncryption = null,
- ?UploadPartUrl $uploadPartUrl = null,
- ?FileUploadMetadata $metadata = null
- ): File {
- if (!$uploadPartUrl instanceof UploadPartUrl) {
- $uploadPartUrl = $this->getUploadPartUrl($fileId);
- }
-
- if (!$metadata instanceof FileUploadMetadata) {
- $metadata = FileUploadMetadata::fromResource($body);
- }
-
- $response = $this->http->request('POST', $uploadPartUrl->getUploadUrl(), [
- 'body' => $body,
- 'headers' => self::filterRequestOptions([
- 'Authorization' => $uploadPartUrl->getAuthorizationToken(),
- 'Content-Length' => $metadata->getLength(),
- File::HEADER_X_BZ_CONTENT_SHA1 => $metadata->getSha1(),
- File::HEADER_X_BZ_PART_NUMBER => $partNumber,
- ], $serverSideEncryption->getHeaders() ?? []),
- ]);
-
- return File::fromArray(json_decode((string) $response->getBody(), true));
+ return File::fromArray(Utils::jsonDecode($response));
}
/**
@@ -802,58 +379,6 @@ public function getFileById(string $fileId, ?string $bucketId = null): File
return $file;
}
- /**
- * Internal method to call the b2_list_parts API
- *
- * @see Client::listParts()
- *
- * @return iterable
- */
- public function listAllParts(
- string $fileId,
- int $startPartNumber = null
- ): iterable {
- $allParts = new AppendIterator();
- $nextPartNumber = $startPartNumber ?? 0;
-
- while ($nextPartNumber !== null) {
- $parts = $this->listParts($fileId, $startPartNumber);
- $nextPartNumber = $parts->getNextPartNumber();
-
- $allParts->append(new NoRewindIterator($parts->getParts()));
- }
-
- return $allParts;
- }
-
- /**
- * Lists information about *all* large file uploads that have been started,
- * but that have not been finished or canceled.
- *
- * @see Client::listUnfinishedLargeFiles()
- *
- * @return iterable
- */
- public function listAllUnfinishedLargeFiles(
- ?string $bucketId = null,
- ?string $namePrefix = null,
- ?string $startFileId = null,
- ?int $maxFileCount = 100
- ): iterable {
-
- $allFiles = new AppendIterator();
- $nextFileId = $startFileId ?? '';
-
- while ($nextFileId !== null) {
- $files = $this->listUnfinishedLargeFiles($bucketId, $namePrefix, $startFileId, $maxFileCount);
- $nextFileId = $files->getNextFileId();
-
- $allFiles->append(new NoRewindIterator($files->getFiles()));
- }
-
- return $allFiles;
- }
-
/**
* Deletes all versions of a file(s) in a bucket.
*
diff --git a/src/Operations/LargeFileOperationsTrait.php b/src/Operations/LargeFileOperationsTrait.php
new file mode 100644
index 0000000..7891324
--- /dev/null
+++ b/src/Operations/LargeFileOperationsTrait.php
@@ -0,0 +1,346 @@
+http->request('POST', Endpoint::CANCEL_LARGE_FILE, [
+ 'json' => [
+ File::ATTRIBUTE_FILE_ID => $fileId,
+ ],
+ ]);
+
+ return File::fromArray(Utils::jsonDecode($response));
+ }
+
+ /**
+ * Copies from an existing B2 file, storing it as a part of a large file which has already been started with
+ * `b2_start_large_file`.
+ *
+ * @link https://www.backblaze.com/b2/docs/b2_copy_part.html
+ *
+ * @b2-capability writeFiles
+ * @b2-capability [readFiles] If the bucket is private.
+ * @b2-transaction Class C
+ *
+ * @param string $sourceFileId The ID of the source file being copied.
+ * @param string $largeFileId The ID of the large file the part will belong to.
+ * @param int $partNumber A number from `1` to `10000`. The parts uploaded for one file must have
+ * contiguous numbers, starting with `1`.
+ * @param string $range The range of bytes to copy.
+ * If not provided, the whole source file will be copied.
+ * @param array $sourceSSE Specifies the parameters for B2 to use for accessing the
+ * source file data using Server-Side Encryption.
+ * @param array $destinationSSE Specifies the parameters for B2 to use for encrypting the
+ * copied data before storing the destination file using Server-Side Encryption.
+ */
+ public function copyPart(
+ string $sourceFileId,
+ string $largeFileId,
+ int $partNumber,
+ ?string $range = null,
+ ?ServerSideEncryption $sourceSSE = null,
+ ?ServerSideEncryption $destinationSSE = null
+ ): File {
+ $response = $this->http->request('POST', Endpoint::COPY_PART, [
+ 'json' => Utils::filterRequestOptions([
+ File::ATTRIBUTE_SOURCE_FILE_ID => $sourceFileId,
+ File::ATTRIBUTE_LARGE_FILE_ID => $largeFileId,
+ File::ATTRIBUTE_PART_NUMBER => $partNumber,
+ ], [
+ File::ATTRIBUTE_RANGE => $range,
+ File::ATTRIBUTE_SOURCE_SSE => $sourceSSE,
+ File::ATTRIBUTE_DESTINATION_SSE => $destinationSSE,
+ ]),
+ ]);
+
+ return File::fromArray(Utils::jsonDecode($response));
+ }
+
+ /**
+ * Converts the parts that have been uploaded into a single B2 file.
+ *
+ * @link https://www.backblaze.com/b2/docs/b2_finish_large_file.html
+ *
+ * @b2-capability writeFiles
+ * @b2-transaction Class A
+ *
+ * @param string $fileId The ID of the large file.
+ * @param string[] $hashes An array of SHA1 checksums of the parts of the large file.
+ *
+ * @return File
+ */
+ public function finishLargeFile(string $fileId, array $hashes)
+ {
+ $response = $this->http->request('POST', Endpoint::FINISH_LARGE_FILE, [
+ 'json' => [
+ File::ATTRIBUTE_FILE_ID => $fileId,
+ File::ATTRIBUTE_PART_SHA1_ARRAY => $hashes,
+ ]
+ ]);
+
+ return File::fromArray(Utils::jsonDecode($response));
+ }
+
+ /**
+ * Gets a URL to use for uploading parts of a large file.
+ *
+ * @link https://www.backblaze.com/b2/docs/b2_get_upload_part_url.html
+ *
+ * @b2-capability writeFiles
+ * @b2-transaction Class A
+ *
+ * @param string $fileId The ID of the large file to upload parts of.
+ */
+ public function getUploadPartUrl(string $fileId): UploadPartUrl
+ {
+ $response = $this->http->request('POST', Endpoint::GET_UPLOAD_PART_URL, [
+ 'json' => [
+ File::ATTRIBUTE_FILE_ID => $fileId
+ ]
+ ]);
+
+ return UploadPartUrl::fromArray(Utils::jsonDecode($response));
+ }
+
+ /**
+ * Lists the parts that have been uploaded for a large file that has not been finished yet.
+ *
+ * @link https://www.backblaze.com/b2/docs/b2_list_parts.html
+ *
+ * @b2-capability writeFiles
+ * @b2-transaction Class C
+ *
+ * @param string $fileId The ID returned by b2_start_large_file. This is the file whose parts will be
+ * listed.
+ * @param int $startPartNumber The first part to return. Used when a query hits the maxKeyCount, and you want to
+ * get more.
+ * @param int $maxPartCount The maximum number of parts to return in the response. The default value is 1000,
+ * and the maximum is 10000. The maximum number of parts returned per transaction
+ * is 1000.
+ * If more than 1000 are returned, the call will be billed as multiple transactions.
+ * @param bool $loop Make API requests until there are no keys left.
+ */
+ public function listParts(
+ string $fileId,
+ ?int $startPartNumber = null,
+ ?int $maxPartCount = 1000
+ ): FilePartList {
+ $response = $this->http->request('POST', Endpoint::LIST_PARTS, [
+ 'json' => Utils::filterRequestOptions([
+ File::ATTRIBUTE_FILE_ID => $fileId
+ ], [
+ File::ATTRIBUTE_START_PART_NUMBER => $startPartNumber,
+ File::ATTRIBUTE_MAX_PART_COUNT => $maxPartCount,
+ ]),
+ ]);
+
+ return FilePartList::fromResponse($response);
+ }
+
+ /**
+ * Lists information about large file uploads that have been started,
+ * but that have not been finished or canceled.
+ *
+ * @link https://www.backblaze.com/b2/docs/b2_list_unfinished_large_files.html
+ *
+ * @b2-capability listFiles
+ * @b2-transaction Class C
+ *
+ * @param string $bucketId The bucket to look for file names in.
+ * @param string $namePrefix Only return files whose names match this prefix.
+ * @param string $startFileId The first upload to return.
+ * @param int $maxFileCount The maximum number of files to return from this call. The default value is 100, and
+ * the maximum allowed is 100.
+ */
+ public function listUnfinishedLargeFiles(
+ ?string $bucketId = null,
+ ?string $namePrefix = null,
+ ?string $startFileId = null,
+ ?int $maxFileCount = 100
+ ): FileList {
+ $response = $this->http->request('POST', Endpoint::LIST_UNFINISHED_LARGE_FILES, [
+ 'json' => Utils::filterRequestOptions([
+ File::ATTRIBUTE_BUCKET_ID => $bucketId ?? $this->getAllowedBucketId(),
+ ], [
+ File::ATTRIBUTE_NAME_PREFIX => $namePrefix,
+ File::ATTRIBUTE_START_FILE_ID => $startFileId,
+ File::ATTRIBUTE_MAX_FILE_COUNT => $maxFileCount,
+ ]),
+ ]);
+
+ return FileList::fromResponse($response);
+ }
+
+ /**
+ * Prepares for uploading the parts of a large file.
+ *
+ * @link https://www.backblaze.com/b2/docs/b2_start_large_file.html
+ *
+ * @b2-capability writeFiles
+ * @b2-transaction Class A
+ *
+ * @param string $bucketId The ID of the bucket that the file will go in.
+ * @param string $fileName The name of the file.
+ * @param string $contentType The MIME type of the content of the file.
+ * @param FileInfo|array $fileInfo A JSON object holding the name/value pairs for the custom file info.
+ */
+ public function startLargeFile(
+ string $fileName,
+ ?string $bucketId = null,
+ ?string $contentType = null,
+ $fileInfo = null,
+ ?array $fileRetention = null,
+ ?array $legalHold = null,
+ ?array $serverSideEncryption = null
+ ): File {
+ if (!$fileInfo instanceof FileInfo) {
+ $fileInfo = FileInfo::fromArray($fileInfo);
+ }
+
+ $response = $this->http->request('POST', Endpoint::START_LARGE_FILE, [
+ 'json' => Utils::filterRequestOptions([
+ File::ATTRIBUTE_BUCKET_ID => $bucketId ?? $this->getAllowedBucketId(),
+ File::ATTRIBUTE_FILE_NAME => $fileName,
+ File::ATTRIBUTE_CONTENT_TYPE => $contentType ?? File::CONTENT_TYPE_AUTO,
+ ], [
+ File::ATTRIBUTE_FILE_INFO => $fileInfo->get(),
+ File::ATTRIBUTE_FILE_RETENTION => $fileRetention,
+ File::ATTRIBUTE_LEGAL_HOLD => $legalHold,
+ File::ATTRIBUTE_SSE => $serverSideEncryption,
+ ])
+ ]);
+
+ return File::fromArray(Utils::jsonDecode($response));
+ }
+
+ /**
+ * Uploads one part of a large file.
+ *
+ * @link https://www.backblaze.com/b2/docs/b2_upload_part.html
+ *
+ * @b2-capability writeFiles
+ * @b2-transaction Class A
+ *
+ * @param string|resource $body The file part to be uploaded. String or stream resource.
+ * @param string $fileId The ID of the large file whose parts you want to upload.
+ * @param int $partNumber The parts uploaded for one file must have contiguous numbers, starting with 1.
+ * @param ServerSideEncryption|array $serverSideEncryption The parameters for B2 to encrypt the uploaded file.
+ * @param UploadPartUrl $uploadPartUrl The upload part authorization data.
+ */
+ public function uploadPart(
+ $body,
+ string $fileId,
+ ?int $partNumber = 1,
+ $serverSideEncryption = null,
+ ?UploadPartUrl $uploadPartUrl = null,
+ ?FileUploadMetadata $metadata = null
+ ): File {
+ if (!$uploadPartUrl instanceof UploadPartUrl) {
+ $uploadPartUrl = $this->getUploadPartUrl($fileId);
+ }
+
+ if (!$metadata instanceof FileUploadMetadata) {
+ $metadata = FileUploadMetadata::fromResource($body);
+ }
+
+ $response = $this->http->request('POST', $uploadPartUrl->getUploadUrl(), [
+ 'body' => $body,
+ 'headers' => self::filterRequestOptions([
+ 'Authorization' => $uploadPartUrl->getAuthorizationToken(),
+ 'Content-Length' => $metadata->getLength(),
+ File::HEADER_X_BZ_CONTENT_SHA1 => $metadata->getSha1(),
+ File::HEADER_X_BZ_PART_NUMBER => $partNumber,
+ ], $serverSideEncryption->getHeaders() ?? []),
+ ]);
+
+ return File::fromArray(Utils::jsonDecode($response));
+ }
+
+ /**
+ * Internal method to call the b2_list_parts API
+ *
+ * @see Client::listParts()
+ *
+ * @return iterable
+ */
+ public function listAllParts(
+ string $fileId,
+ int $startPartNumber = null
+ ): iterable {
+ $allParts = new AppendIterator();
+ $nextPartNumber = $startPartNumber ?? 0;
+
+ while ($nextPartNumber !== null) {
+ $parts = $this->listParts($fileId, $startPartNumber);
+ $nextPartNumber = $parts->getNextPartNumber();
+
+ $allParts->append(new NoRewindIterator($parts->getParts()));
+ }
+
+ return $allParts;
+ }
+
+ /**
+ * Lists information about *all* large file uploads that have been started,
+ * but that have not been finished or canceled.
+ *
+ * @see Client::listUnfinishedLargeFiles()
+ *
+ * @return iterable
+ */
+ public function listAllUnfinishedLargeFiles(
+ ?string $bucketId = null,
+ ?string $namePrefix = null,
+ ?string $startFileId = null,
+ ?int $maxFileCount = 100
+ ): iterable {
+
+ $allFiles = new AppendIterator();
+ $nextFileId = $startFileId ?? '';
+
+ while ($nextFileId !== null) {
+ $files = $this->listUnfinishedLargeFiles($bucketId, $namePrefix, $startFileId, $maxFileCount);
+ $nextFileId = $files->getNextFileId();
+
+ $allFiles->append(new NoRewindIterator($files->getFiles()));
+ }
+
+ return $allFiles;
+ }
+
+}
diff --git a/src/Operations/UploadOperationsTrait.php b/src/Operations/UploadOperationsTrait.php
new file mode 100644
index 0000000..ba1b96f
--- /dev/null
+++ b/src/Operations/UploadOperationsTrait.php
@@ -0,0 +1,101 @@
+http->request('POST', Endpoint::GET_UPLOAD_URL, [
+ 'json' => [
+ File::ATTRIBUTE_BUCKET_ID => $bucketId ?? $this->getAllowedBucketId()
+ ]
+ ]);
+
+ return UploadUrl::fromArray(Utils::jsonDecode($response));
+ }
+
+ /**
+ * Uploads a file to a bucket and returns the uploaded file as an object.
+ *
+ * @link https://www.backblaze.com/b2/docs/b2_upload_file.html
+ *
+ * @b2-capability writeFiles
+ * @b2-transaction Class A
+ *
+ * @param string $bucketId The ID of the bucket to upload the file to.
+ * @param string $fileName The name of the file.
+ * @param string|resource $body The file to be uploaded. String or stream resource.
+ * @param string $contentType The MIME type of the content of the file.
+ * @param FileInfo|array $fileInfo The custom file info to add to the uploaded file.
+ * @param ServerSideEncryption|array $serverSideEncryption The parameters for B2 to encrypt the uploaded file.
+ * @param UploadUrl $uploadUrl The upload authorization data.
+ */
+ public function uploadFile(
+ string $fileName,
+ ?string $bucketId = null,
+ $body,
+ ?string $contentType = null,
+ $fileInfo = null,
+ $serverSideEncryption = null,
+ ?UploadUrl $uploadUrl = null
+ ): File {
+ if (!$fileInfo instanceof FileInfo) {
+ $fileInfo = FileInfo::fromArray($fileInfo ?? []);
+ }
+
+ if (!$serverSideEncryption instanceof ServerSideEncryption) {
+ $serverSideEncryption = ServerSideEncryption::fromArray($serverSideEncryption ?? []);
+ }
+
+ if (!$uploadUrl instanceof UploadUrl) {
+ $uploadUrl = $this->getUploadUrl($bucketId);
+ }
+
+ $uploadMetadata = FileUploadMetadata::fromResource($body);
+ $mtime = $uploadMetadata->getLastModifiedTimestamp();
+ if ($mtime > 0) {
+ $fileInfo->setLastModifiedTimestamp($mtime);
+ }
+
+ $response = $this->http->request('POST', $uploadUrl->getUploadUrl(), [
+ 'body' => $body,
+ 'headers' => Utils::filterRequestOptions(
+ [
+ 'Authorization' => $uploadUrl->getAuthorizationToken(),
+ 'Content-Type' => $contentType ?? File::CONTENT_TYPE_AUTO,
+ 'Content-Length' => $uploadMetadata->getLength(),
+ File::HEADER_X_BZ_CONTENT_SHA1 => $uploadMetadata->getSha1(),
+ File::HEADER_X_BZ_FILE_NAME => $fileName, //rawurlencode($fileName),// urlencode($fileName),
+ ],
+ ($serverSideEncryption->getHeaders() ?? []),
+ ($fileInfo->getHeaders() ?? [])
+ ),
+ ]);
+
+ return File::fromArray(Utils::jsonDecode($response));
+ }
+}
\ No newline at end of file
diff --git a/src/Response/AbstractListResponse.php b/src/Response/AbstractListResponse.php
index 118fb75..b80a48e 100644
--- a/src/Response/AbstractListResponse.php
+++ b/src/Response/AbstractListResponse.php
@@ -6,7 +6,7 @@
use Zaxbux\BackblazeB2\Traits\ObjectIterableTrait;
-
+/** @package Zaxbux\BackblazeB2\Response */
abstract class AbstractListResponse extends AbstractResponse {
use ObjectIterableTrait;
}
diff --git a/src/Response/AbstractResponse.php b/src/Response/AbstractResponse.php
index 66ff502..ad442d4 100644
--- a/src/Response/AbstractResponse.php
+++ b/src/Response/AbstractResponse.php
@@ -4,9 +4,11 @@
namespace Zaxbux\BackblazeB2\Response;
+use JsonException;
use Psr\Http\Message\ResponseInterface;
+use Zaxbux\BackblazeB2\Utils;
-
+/** @package Zaxbux\BackblazeB2\Response */
abstract class AbstractResponse {
/** @var ResponseInterface */
@@ -18,7 +20,7 @@ abstract class AbstractResponse {
* @param ResponseInterface $response B2 API response.
* @return AbstractListResponse
*/
- abstract public static function create(ResponseInterface $response): AbstractResponse;
+ abstract public static function fromResponse(ResponseInterface $response): AbstractResponse;
public function __construct(ResponseInterface $response)
{
@@ -34,4 +36,18 @@ public function getRawResponse(): ResponseInterface
{
return $this->rawResponse;
}
+
+ /**
+ * Decode the response body as JSON and return the array.
+ *
+ * @return null|array Returns null if the response could not be decoded as JSON.
+ */
+ public function json(): ?array
+ {
+ try {
+ return Utils::jsonDecode((string) $this->rawResponse->getBody());
+ } catch (JsonException $ex) {}
+
+ return null;
+ }
}
diff --git a/src/Response/BucketList.php b/src/Response/BucketList.php
index 6c92358..123e8d2 100644
--- a/src/Response/BucketList.php
+++ b/src/Response/BucketList.php
@@ -4,14 +4,14 @@
namespace Zaxbux\BackblazeB2\Response;
-use Generator;
-use GuzzleHttp\Utils;
+use Iterator;
use Psr\Http\Message\ResponseInterface;
use Zaxbux\BackblazeB2\Object\Bucket;
+use Zaxbux\BackblazeB2\Utils;
use function iterator_to_array;
-
+/** @package Zaxbux\BackblazeB2\Response */
class BucketList extends AbstractListResponse {
/** @var iterable */
@@ -25,7 +25,7 @@ public function __construct(array $buckets)
/**
* Get the value of buckets.
*/
- public function getBuckets(): Generator
+ public function getBuckets(): Iterator
{
return $this->buckets;
}
@@ -35,7 +35,7 @@ public function getBuckets(): Generator
*
* @return iterable
*/
- public function getBucketsArray(): iterable
+ public function getBucketsArray(): array
{
return iterator_to_array($this->getBuckets());
}
@@ -45,10 +45,10 @@ public function getBucketsArray(): iterable
*
* @return BucketList
*/
- public static function create(ResponseInterface $response): BucketList
+ public static function fromResponse(ResponseInterface $response): BucketList
{
- $responseData = Utils::jsonDecode((string) $response->getBody(), true);
+ $buckets = Utils::jsonDecode((string) $response->getBody())[Bucket::ATTRIBUTE_BUCKETS];
- return new BucketList($responseData[Bucket::ATTRIBUTE_BUCKETS]);
+ return new BucketList($buckets);
}
}
\ No newline at end of file
diff --git a/src/Response/FileDownload.php b/src/Response/FileDownload.php
index 4ddad71..d34b6aa 100644
--- a/src/Response/FileDownload.php
+++ b/src/Response/FileDownload.php
@@ -12,8 +12,7 @@
/**
* A response representing a file download.
- *
-
+ * @package Zaxbux\BackblazeB2\Response
*/
class FileDownload extends AbstractResponse {
@@ -100,7 +99,7 @@ public function isFile(): bool
*
* @return FileDownload
*/
- public static function create(
+ public static function fromResponse(
ResponseInterface $response,
?string $filePath = null
): FileDownload {
diff --git a/src/Response/FileList.php b/src/Response/FileList.php
index eb387a7..451725c 100644
--- a/src/Response/FileList.php
+++ b/src/Response/FileList.php
@@ -2,13 +2,12 @@
namespace Zaxbux\BackblazeB2\Response;
-use Generator;
-use GuzzleHttp\Utils;
use Iterator;
use Psr\Http\Message\ResponseInterface;
use Zaxbux\BackblazeB2\Object\File;
+use Zaxbux\BackblazeB2\Utils;
-
+/** @package Zaxbux\BackblazeB2\Response */
class FileList extends AbstractListResponse {
/** @var Iterator */
@@ -78,7 +77,7 @@ public function getNextFileName(): ?string
*
* @return FileList
*/
- public static function create(ResponseInterface $response): FileList
+ public static function fromResponse(ResponseInterface $response): FileList
{
$data = Utils::jsonDecode((string) $response->getBody(), true);
diff --git a/src/Response/FilePartList.php b/src/Response/FilePartList.php
index 929355c..21c3670 100644
--- a/src/Response/FilePartList.php
+++ b/src/Response/FilePartList.php
@@ -4,10 +4,9 @@
use Psr\Http\Message\ResponseInterface;
use Zaxbux\BackblazeB2\Object\File;
+use Zaxbux\BackblazeB2\Utils;
-use function GuzzleHttp\json_decode;
-
-
+/** @package Zaxbux\BackblazeB2\Response */
class FilePartList extends AbstractListResponse {
/** @var iterable */
@@ -47,9 +46,9 @@ public function getNextPartNumber(): ?string
*
* @return FilePartList
*/
- public static function create(ResponseInterface $response): FilePartList
+ public static function fromResponse(ResponseInterface $response): FilePartList
{
- $responseData = json_decode((string) $response->getBody(), true);
+ $responseData = Utils::jsonDecode((string) $response->getBody(), true);
return new FilePartList(
$responseData[File::ATTRIBUTE_PARTS],
diff --git a/src/Response/KeyList.php b/src/Response/KeyList.php
index fc495e9..0de0bde 100644
--- a/src/Response/KeyList.php
+++ b/src/Response/KeyList.php
@@ -10,6 +10,7 @@
use Zaxbux\BackblazeB2\Object\Key;
+/** @package Zaxbux\BackblazeB2\Response */
class KeyList extends AbstractListResponse {
/** @var iterable */
@@ -52,7 +53,7 @@ public function getNextApplicationKeyId(): ?string
*
* @return KeyList
*/
- public static function create(ResponseInterface $response): KeyList
+ public static function fromResponse(ResponseInterface $response): KeyList
{
$responseData = Utils::jsonDecode((string) $response->getBody(), true);
diff --git a/src/Traits/ApplyToAllFileVersionsTrait.php b/src/Traits/ApplyToAllFileVersionsTrait.php
new file mode 100644
index 0000000..3a7539b
--- /dev/null
+++ b/src/Traits/ApplyToAllFileVersionsTrait.php
@@ -0,0 +1,22 @@
+withFileName($fileName);
+ }
+}
\ No newline at end of file
diff --git a/src/Traits/ObjectIterableTrait.php b/src/Traits/ObjectIterableTrait.php
index 4d75128..e53eddc 100644
--- a/src/Traits/ObjectIterableTrait.php
+++ b/src/Traits/ObjectIterableTrait.php
@@ -4,13 +4,13 @@
namespace Zaxbux\BackblazeB2\Traits;
+use Generator;
use RuntimeException;
use Zaxbux\BackblazeB2\Interfaces\B2ObjectInterface;
+/** @package Zaxbux\BackblazeB2\Traits */
trait ObjectIterableTrait
{
- //abstract public static function fromArray(array $data): B2ObjectInterface;
-
/**
*
* @param string $object
@@ -20,7 +20,7 @@ trait ObjectIterableTrait
*
* @throws RuntimeException
*/
- public static function createObjectIterable(string $object, array $data): iterable
+ public static function createObjectIterable(string $object, array $data): Generator
{
if (!method_exists($object, 'fromArray')) {
throw new RuntimeException($object .' does not implement fromArray() method');
diff --git a/src/Utils.php b/src/Utils.php
index 247a7b0..331fad8 100644
--- a/src/Utils.php
+++ b/src/Utils.php
@@ -6,8 +6,10 @@
use InvalidArgumentException;
use GuzzleHttp\Utils as GuzzleUtils;
+use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\StreamInterface;
+/** @package Zaxbux\BackblazeB2 */
final class Utils
{
/**
@@ -93,4 +95,13 @@ public static function getUserAgent(string $appName): string
{
return sprintf('%s %s+php/%s %s', $appName, Client::USER_AGENT_PREFIX . Client::VERSION, PHP_VERSION, GuzzleUtils::defaultUserAgent());
}
+
+ public static function jsonDecode($data): array
+ {
+ if ($data instanceof ResponseInterface) {
+ $data = (string) $data->getBody();
+ }
+
+ return json_decode($data, true, 512, JSON_THROW_ON_ERROR);
+ }
}
\ No newline at end of file
diff --git a/tests/BucketObjectTest.php b/tests/BucketObjectTest.php
index dc66864..ae71629 100644
--- a/tests/BucketObjectTest.php
+++ b/tests/BucketObjectTest.php
@@ -31,7 +31,7 @@ public function testBucketList()
public function testBucketListFromResponse()
{
- $bucketList = BucketList::create(new Response(200, [], json_encode([
+ $bucketList = BucketList::fromResponse(new Response(200, [], json_encode([
Bucket::ATTRIBUTE_BUCKETS => static::createBuckets(100),
])));
diff --git a/tests/ClientBucketOperationsTest.php b/tests/ClientBucketOperationsTest.php
index 6963b28..5bd3e68 100644
--- a/tests/ClientBucketOperationsTest.php
+++ b/tests/ClientBucketOperationsTest.php
@@ -2,12 +2,14 @@
namespace tests;
+use BlastCloud\Guzzler\Expectation;
use Zaxbux\BackblazeB2\Client;
use Zaxbux\BackblazeB2\Object\Bucket;
use Zaxbux\BackblazeB2\Object\Bucket\BucketType;
use Zaxbux\BackblazeB2\Exceptions\Request\B2APIException;
use Zaxbux\BackblazeB2\Exceptions\Request\BadRequestException;
use Zaxbux\BackblazeB2\Exceptions\Request\DuplicateBucketNameException;
+use Zaxbux\BackblazeB2\Http\Endpoint;
class ClientBucketOperationsTest extends ClientTestBase
{
@@ -99,8 +101,8 @@ public function testUpdateBucketToPublic()
);
$bucket = $this->client->updateBucket(
- 'bucketId',
- BucketType::PUBLIC
+ BucketType::PUBLIC,
+ 'bucketId'
);
$this->assertInstanceOf(Bucket::class, $bucket);
@@ -140,9 +142,33 @@ public function testDeleteBucket()
$this->guzzler->expects($this->once())
->post(static::getEndpointUri(Endpoint::DELETE_BUCKET));
- $this->assertInstanceOf(Bucket::class, $this->client->deleteBucket(
- 'bucketId'
- ));
+ $bucket = $this->client->deleteBucket('bucketId');
+
+ $this->assertInstanceOf(Bucket::class, $bucket);
+ }
+
+ public function testDeleteBucketWithFiles()
+ {
+ $this->guzzler->expects($this->once())
+ ->post(self::getEndpointUri(Endpoint::LIST_FILE_VERSIONS));
+ $this->guzzler->expects($this->exactly(3))
+ ->post(self::getEndpointUri(Endpoint::DELETE_FILE_VERSION));
+ $this->guzzler->expects($this->once())
+ ->post(static::getEndpointUri(Endpoint::DELETE_BUCKET));
+
+ $this->guzzler->queueResponse(
+ MockResponse::fromFile('list_file_versions.json'),
+ );
+
+ $this->guzzler->queueMany(MockResponse::fromFile('delete_file.json'), 3);
+
+ $this->guzzler->queueResponse(
+ MockResponse::fromFile('delete_bucket.json'),
+ );
+
+ $bucket = $this->client->deleteBucket('bucketId', true);
+
+ $this->assertInstanceOf(Bucket::class, $bucket);
}
public function testBadJsonThrownDeletingNonExistentBucket()
@@ -158,7 +184,7 @@ public function testBadJsonThrownDeletingNonExistentBucket()
public function testBucketNotEmptyThrownDeletingNonEmptyBucket()
{
- $this->expectException(B2APIException::class);
+ $this->expectException(BadRequestException::class);
$this->guzzler->queueResponse(
MockResponse::fromFile('bucket_not_empty.json', 400),
@@ -166,4 +192,28 @@ public function testBucketNotEmptyThrownDeletingNonEmptyBucket()
$this->client->deleteBucket('bucketId');
}
+
+ public function testGetBucketById()
+ {
+ $this->guzzler->expects($this->once())
+ ->post(static::getEndpointUri(Endpoint::LIST_BUCKETS));
+
+ $this->guzzler->queueResponse(MockResponse::fromFile('get_bucket.json'));
+
+ $bucket = $this->client->getBucketById('bucketId');
+
+ static::assertInstanceOf(Bucket::class, $bucket);
+ }
+
+ public function testGetBucketByName()
+ {
+ $this->guzzler->expects($this->once())
+ ->post(static::getEndpointUri(Endpoint::LIST_BUCKETS));
+
+ $this->guzzler->queueResponse(MockResponse::fromFile('get_bucket.json'));
+
+ $bucket = $this->client->getBucketByName('bucket_name');
+
+ static::assertInstanceOf(Bucket::class, $bucket);
+ }
}
diff --git a/tests/ClientCreationTest.php b/tests/ClientCreationTest.php
new file mode 100644
index 0000000..8183d20
--- /dev/null
+++ b/tests/ClientCreationTest.php
@@ -0,0 +1,52 @@
+assertInstanceOf(Client::class, new Client([
+ '000000000000bb80000000000',
+ 'abcdefghijklmnopqrstuvwxyz01234',
+ ]));
+ }
+
+ public function testNewClientWithOptionsArray()
+ {
+ $client = new Client([
+ 'applicationName' => 'app_name',
+ 'applicationKeyId' => '000000000000bb80000000000',
+ 'applicationKey' => 'abcdefghijklmnopqrstuvwxyz01234',
+ ]);
+
+ $this->assertInstanceOf(Client::class, $client);
+ $this->assertEquals('app_name', $client->getConfig()->applicationName());
+ }
+
+ public function testNewClientWithConfig()
+ {
+ $client = new Client(new Config(
+ '000000000000bb80000000000',
+ 'abcdefghijklmnopqrstuvwxyz01234',
+ [
+ 'applicationName' => 'app_name',
+ ]
+ ));
+
+ $this->assertInstanceOf(Client::class, $client);
+ $this->assertEquals('app_name', $client->getConfig()->applicationName());
+ }
+
+ public function testCreateClient()
+ {
+ $this->assertInstanceOf(Client::class, Client::create([
+ 'applicationKeyId' => '000000000000bb80000000000',
+ 'applicationKey' => 'abcdefghijklmnopqrstuvwxyz01234',
+ ]));
+ }
+}
diff --git a/tests/ClientExceptionsTest.php b/tests/ClientExceptionsTest.php
index 390553b..842fe48 100644
--- a/tests/ClientExceptionsTest.php
+++ b/tests/ClientExceptionsTest.php
@@ -92,8 +92,8 @@ public function exceptionDataProvider(): array
['range_not_satisfiable', 416, RangeNotSatisfiableException::class],
- ['service_unavailable', 503, ServiceUnavailableException::class],
- ['bad_request', 503, BadRequestException::class],
+ //['service_unavailable', 503, ServiceUnavailableException::class],
+ //['bad_request', 503, BadRequestException::class],
];
}
}
diff --git a/tests/ClientFileOperationsTest.php b/tests/ClientFileOperationsTest.php
index fbbfc24..418f34f 100644
--- a/tests/ClientFileOperationsTest.php
+++ b/tests/ClientFileOperationsTest.php
@@ -5,129 +5,263 @@
use Zaxbux\BackblazeB2\Response\FileList;
use Zaxbux\BackblazeB2\Object\File;
use Zaxbux\BackblazeB2\Exceptions\Request\BadRequestException;
+use Zaxbux\BackblazeB2\Http\Endpoint;
+use Zaxbux\BackblazeB2\Object\File\FileLock;
class ClientFileOperationsTest extends ClientTestBase
{
- public function testListFilesHandlesMultiplePages()
+ public function testCopyFile()
{
$this->guzzler->queueResponse(
- MockResponse::fromFile('list_files_page1.json'),
- MockResponse::fromFile('list_files_page2.json'),
+ MockResponse::fromFile('copy_file.json'),
);
- $files = $this->client->listAllFileNames('bucketId');
+ $newFile = $this->client->copyFile(
+ 'fileId',
+ 'newFileName'
+ );
- $this->assertIsIterable($files);
- $this->assertInstanceOf(File::class, $files->current());
- $this->assertCount(1500, $files);
+ $this->assertInstanceOf(File::class, $newFile);
+ $this->assertEquals('newFileName', $newFile->getName());
+ $this->assertEquals('newFileId', $newFile->getId());
}
- public function testListFilesReturnsEmptyArrayWithNoFiles()
+ public function testDeleteFileVersion()
{
$this->guzzler->queueResponse(
- MockResponse::fromFile('list_files_empty.json'),
+ MockResponse::fromFile('get_file.json'),
+ MockResponse::fromFile('delete_file.json'),
);
- $response = $this->client->listFileNames('bucketId');
- $this->assertInstanceOf(FileList::class, $response);
- $files = $response->getFilesArray();
- $this->assertCount(0, $files);
+ $fileId = $this->client->getFileByName('Test file.bin', 'bucketId')->getId();
+
+ $this->assertInstanceOf(File::class, $this->client->deleteFileVersion('Test file.bin', $fileId));
}
+
- public function testGetFile()
+ public function testDeleteFileWithoutName()
{
$this->guzzler->queueResponse(
- MockResponse::fromFile('get_file.json'),
+ MockResponse::fromFile('list_file_versions.json'),
+ MockResponse::fromFile('delete_file.json'),
);
- $file = $this->client->getFileById('fileId', 'bucketId');
+ $this->guzzler->expects($this->once())
+ ->post(static::getEndpointUri(Endpoint::LIST_FILE_VERSIONS))
+ ->post(static::getEndpointUri(Endpoint::DELETE_FILE_VERSION));
+
+ $file = $this->client->deleteFileVersion('fileId');
$this->assertInstanceOf(File::class, $file);
}
- public function testGettingNonExistentFileThrowsException()
+ public function testDeletingNonExistentFileThrowsException()
{
$this->expectException(BadRequestException::class);
$this->guzzler->queueResponse(
- MockResponse::fromFile('get_file_non_existent.json', 400),
+ MockResponse::fromFile('delete_file_non_existent.json', 400),
);
- $this->client->getFileById('fileId', 'bucketId');
+ $this->assertNull($this->client->deleteFileVersion('fileId', 'fileName'));
+ }
+
+ public function testGetFileInfo()
+ {
+ $this->guzzler->expects($this->once())
+ ->post(static::getEndpointUri(Endpoint::GET_FILE_INFO))
+ ->withJson(['fileId' => 'file_id']);
+
+ $this->guzzler->queueResponse(MockResponse::fromFile('get_file_info.json'));
+
+ $file = $this->client->getFileInfo('file_id');
+
+ $this->assertInstanceOf(File::class, $file);
}
- public function testDeleteFile()
+ public function testHideFile()
{
$this->guzzler->queueResponse(
- MockResponse::fromFile('get_file.json'),
- MockResponse::fromFile('delete_file.json'),
+ MockResponse::fromFile('hide_file.json'),
);
- $fileId = $this->client->getFileByName('Test file.bin', 'bucketId')->getId();
+ $this->guzzler->expects($this->once())
+ ->post(static::getEndpointUri(Endpoint::HIDE_FILE));
- $this->assertInstanceOf(File::class, $this->client->deleteFileVersion('Test file.bin', $fileId));
+ $file = $this->client->hideFile('testfile.bin', 'bucketId');
+
+ $this->assertInstanceOf(File::class, $file);
}
-
- public function testDeleteFileRetrievesFileNameWhenNotProvided()
+ public function testListFileNames()
{
$this->guzzler->queueResponse(
MockResponse::fromFile('list_file_versions.json'),
);
- $this->guzzler->queueMany(MockResponse::fromFile('delete_file.json'), 3);
- $this->guzzler->expects($this->once())->post(static::getEndpointUri(Endpoint::LIST_FILE_VERSIONS));
- $this->guzzler->expects($this->exactly(3))->post(static::getEndpointUri(Endpoint::DELETE_FILE_VERSION));
+ $this->guzzler->expects($this->once())
+ ->post(static::getEndpointUri(Endpoint::LIST_FILE_NAMES));
- $response = $this->client->deleteAllFileVersions('fileId', null, null, null, 'bucketId');
+ $response = $this->client->listFileNames('bucketId');
$this->assertInstanceOf(FileList::class, $response);
-
- $files = $response->getFilesArray();
- $this->assertCount(3, $files);
- $this->assertContainsOnlyInstancesOf(File::class, $files);
+ $this->assertCount(3, $response->getFilesArray());
+ $this->assertEquals(null, $response->getNextFileId());
+ $this->assertEquals(null, $response->getNextFileName());
}
- public function testDeletingNonExistentFileThrowsException()
+ public function testListFileVersions()
{
- $this->expectException(BadRequestException::class);
+ $this->guzzler->queueResponse(
+ MockResponse::fromFile('list_file_versions.json'),
+ );
+
+ $this->guzzler->expects($this->once())
+ ->post(static::getEndpointUri(Endpoint::LIST_FILE_VERSIONS));
+ $response = $this->client->listFileVersions('bucketId');
+
+ $this->assertInstanceOf(FileList::class, $response);
+ $this->assertCount(3, $response->getFilesArray());
+ $this->assertEquals(null, $response->getNextFileId());
+ $this->assertEquals(null, $response->getNextFileName());
+ }
+
+ public function testUpdateLegalFileHold()
+ {
$this->guzzler->queueResponse(
- MockResponse::fromFile('delete_file_non_existent.json', 400),
+ MockResponse::fromFile('update_file_legal_hold.json'),
);
- $this->assertNull($this->client->deleteFileVersion('fileId', 'fileName'));
+ $this->guzzler->expects($this->once())
+ ->post(static::getEndpointUri(Endpoint::UPDATE_FILE_LEGAL_HOLD));
+
+ $file = $this->client->updateFileLegalHold('file_id', 'file_name', FileLock::LEGAL_HOLD_ENABLED);
+
+ $this->assertInstanceOf(File::class, $file);
}
- public function testCopyFile()
+ public function testUpdateLegalFileHoldWithoutFileName()
{
$this->guzzler->queueResponse(
- MockResponse::fromFile('copy_file.json'),
+ MockResponse::fromFile('list_file_versions.json'),
+ MockResponse::fromFile('update_file_legal_hold.json'),
);
- $newFile = $this->client->copyFile(
- 'fileId',
- 'newFileName'
+ $this->guzzler->expects($this->once())
+ ->post(static::getEndpointUri(Endpoint::UPDATE_FILE_LEGAL_HOLD));
+
+ $file = $this->client->updateFileLegalHold('file_id', null, FileLock::LEGAL_HOLD_ENABLED);
+
+ $this->assertInstanceOf(File::class, $file);
+ }
+
+ public function testUpdateFileRetention()
+ {
+ $this->guzzler->queueResponse(
+ MockResponse::fromFile('update_file_retention.json'),
);
- $this->assertInstanceOf(File::class, $newFile);
- $this->assertEquals('newFileName', $newFile->getName());
- $this->assertEquals('newFileId', $newFile->getId());
+ $this->guzzler->expects($this->once())
+ ->post(static::getEndpointUri(Endpoint::UPDATE_FILE_RETENTION));
+
+ $file = $this->client->updateFileRetention('file_id', 'file_name', [
+ 'mode' => '',
+ 'remainUntilTimestamp' => 0
+ ]);
+
+ $this->assertInstanceOf(File::class, $file);
}
- public function testHideFile()
+ public function testUpdateFileRetentionWithoutFileName()
{
$this->guzzler->queueResponse(
- MockResponse::fromFile('hide_file.json'),
+ MockResponse::fromFile('list_file_versions.json'),
+ MockResponse::fromFile('update_file_retention.json'),
);
$this->guzzler->expects($this->once())
- ->post(static::getEndpointUri(Endpoint::AUTHORIZE_ACCOUNT))
- ->post(static::getEndpointUri(Endpoint::HIDE_FILE));
+ ->post(static::getEndpointUri(Endpoint::UPDATE_FILE_RETENTION));
- $file = $this->client->hideFile('testfile.bin', 'bucketId');
+ $file = $this->client->updateFileRetention('file_id', null, [
+ 'mode' => '',
+ 'remainUntilTimestamp' => 0
+ ]);
$this->assertInstanceOf(File::class, $file);
}
+
+ public function testListAllFileNames()
+ {
+ $this->guzzler->queueResponse(
+ MockResponse::fromFile('list_files_page1.json'),
+ MockResponse::fromFile('list_files_page2.json'),
+ );
+
+ $files = $this->client->listAllFileNames('bucketId');
+
+ $this->assertIsIterable($files);
+ $this->assertInstanceOf(File::class, $files->current());
+ $this->assertCount(1500, $files);
+ }
+
+ public function testListFileNamesWithNoFiles()
+ {
+ $this->guzzler->queueResponse(
+ MockResponse::fromFile('list_files_empty.json'),
+ );
+
+ $response = $this->client->listFileNames('bucketId');
+ $this->assertInstanceOf(FileList::class, $response);
+ $files = $response->getFilesArray();
+ $this->assertCount(0, $files);
+ }
+
+ public function testListAllFileVersions()
+ {
+
+ }
+
+ public function testGetFileById()
+ {
+ $this->guzzler->queueResponse(
+ MockResponse::fromFile('get_file.json'),
+ );
+
+ $file = $this->client->getFileById('fileId', 'bucketId');
+
+ $this->assertInstanceOf(File::class, $file);
+ }
+
+ public function testGettingNonExistentFileThrowsException()
+ {
+ $this->expectException(BadRequestException::class);
+
+ $this->guzzler->queueResponse(
+ MockResponse::fromFile('get_file_non_existent.json', 400),
+ );
+
+ $this->client->getFileById('fileId', 'bucketId');
+ }
+
+ public function testDeleteAllFileVersions()
+ {
+ $this->guzzler->queueResponse(
+ MockResponse::fromFile('list_file_versions.json'),
+ );
+ $this->guzzler->queueMany(MockResponse::fromFile('delete_file.json'), 3);
+
+ $this->guzzler->expects($this->once())->post(static::getEndpointUri(Endpoint::LIST_FILE_VERSIONS));
+ $this->guzzler->expects($this->exactly(3))->post(static::getEndpointUri(Endpoint::DELETE_FILE_VERSION));
+
+ $response = $this->client->deleteAllFileVersions('fileId', null, null, null, 'bucketId');
+
+ $this->assertInstanceOf(FileList::class, $response);
+
+ $files = $response->getFilesArray();
+ $this->assertCount(3, $files);
+ $this->assertContainsOnlyInstancesOf(File::class, $files);
+ }
+
}
diff --git a/tests/ClientTest.php b/tests/ClientTest.php
index 336f89a..e40227d 100644
--- a/tests/ClientTest.php
+++ b/tests/ClientTest.php
@@ -2,6 +2,7 @@
namespace tests;
+use GuzzleHttp\ClientInterface;
use GuzzleHttp\Psr7\Response;
use Zaxbux\BackblazeB2\Client;
use Zaxbux\BackblazeB2\Config;
@@ -10,33 +11,17 @@
class ClientTest extends ClientTestBase
{
- protected function afterSetUp() {
- return;
- }
-
public function testClient()
{
$this->assertInstanceOf(Client::class, $this->client);
- }
-
- public function testClientConfig()
- {
$this->assertInstanceOf(Config::class, $this->client->getConfig());
+ $this->assertInstanceOf(ClientInterface::class, $this->client->getHttpClient());
+ $this->assertInstanceOf(AccountAuthorization::class, $this->client->accountAuthorization());
+ $this->assertEquals('bucket_id', $this->client->getAllowedBucketId());
+ $this->assertEquals('bucket_name', $this->client->getAllowedBucketName());
}
- public function testClientAuthorizeAccount()
- {
- $this->guzzler->expects($this->exactly(2))
- ->get(Client::BASE_URI . Client::B2_API_VERSION . Endpoint::AUTHORIZE_ACCOUNT)
- ->withHeader('Authorization', 'Basic MDAwMDAwMDAwMDAwYmI4MDAwMDAwMDAwMDphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ejAxMjM0');
-
- $this->guzzler->queueResponse(
- MockResponse::json(static::ACCOUNT_AUTHORIZATION),
- );
-
- $this->assertInstanceOf(AccountAuthorization::class, $this->client->authorizeAccount());
- }
-
+ /*
public function testRetryMiddleware()
{
$this->guzzler->queueMany(new Response(429, ['Retry-After' => 1]), 4);
@@ -48,7 +33,9 @@ public function testRetryMiddleware()
return $expect->post(static::getEndpointUri(Endpoint::LIST_BUCKETS));
});
}
+ */
+ /*
public function testThrowsTooManyRequestsException()
{
$this->expectException(TooManyRequestsException::class);
@@ -56,7 +43,6 @@ public function testThrowsTooManyRequestsException()
$this->guzzler->queueMany(new Response(429, ['Retry-After' => 1]), 5);
$this->client->getHttpClient()->request('POST', static::getEndpointUri(Endpoint::LIST_BUCKETS));
-
-
}
+ */
}
diff --git a/tests/ClientTestBase.php b/tests/ClientTestBase.php
index 30a4fe4..678a7ad 100644
--- a/tests/ClientTestBase.php
+++ b/tests/ClientTestBase.php
@@ -9,6 +9,8 @@
use PHPUnit\Framework\TestCase;
use Zaxbux\BackblazeB2\Client;
use tests\Traits\EndpointHelpersTrait;
+use Zaxbux\BackblazeB2\Http\Endpoint;
+use Zaxbux\BackblazeB2\Utils;
abstract class ClientTestBase extends TestCase
{
@@ -20,7 +22,10 @@ abstract class ClientTestBase extends TestCase
*/
protected const ACCOUNT_AUTHORIZATION = [
"accountId" => "000000000000bb8",
- "allowed" => [],
+ "allowed" => [
+ 'bucketId' => 'bucket_id',
+ 'bucketName' => 'bucket_name'
+ ],
"apiUrl" => "https://apiNNN.backblaze.com.test",
"authorizationToken" => "0_0000000000008f80000000000_zzzzzzzz_zzzzzz_acct_zzzzzzzzzzzzzzzzzzzzzzzzzzzz",
"downloadUrl" => "https://fNNN.backblaze.com.test",
@@ -59,11 +64,15 @@ protected function setUp(): void
}
protected function afterSetUp() {
- $this->guzzler->expects($this->once())->get(Client::BASE_URI . Client::B2_API_VERSION . Endpoint::AUTHORIZE_ACCOUNT);
+ $this->guzzler->expects($this->atLeast(0))
+ ->get(Client::BASE_URI . Client::B2_API_VERSION . Endpoint::AUTHORIZE_ACCOUNT)
+ ->withHeader('Authorization', 'Basic MDAwMDAwMDAwMDAwYmI4MDAwMDAwMDAwMDphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ejAxMjM0')
+ ->withHeader('User-Agent', Utils::getUserAgent('app_name'));
}
protected function clientInit() {
return [
+ 'applicationName' => 'app_name',
'applicationKeyId' => '000000000000bb80000000000',
'applicationKey' => 'abcdefghijklmnopqrstuvwxyz01234',
'handler' => $this->guzzler->getHandlerStack()
diff --git a/tests/ClientUploadTest.php b/tests/ClientUploadTest.php
index beee87d..ab39091 100644
--- a/tests/ClientUploadTest.php
+++ b/tests/ClientUploadTest.php
@@ -4,6 +4,7 @@
use Zaxbux\BackblazeB2\Utils as ClientUtils;
use Zaxbux\BackblazeB2\Helpers\UploadHelper;
+use Zaxbux\BackblazeB2\Http\Endpoint;
use Zaxbux\BackblazeB2\Object\File;
use Zaxbux\BackblazeB2\Object\File\FileInfo;
diff --git a/tests/KeyObjectTest.php b/tests/KeyObjectTest.php
index 421f603..cffdb2f 100644
--- a/tests/KeyObjectTest.php
+++ b/tests/KeyObjectTest.php
@@ -31,7 +31,7 @@ public function testKeyList()
public function testKeyListFromResponse()
{
- $keyList = KeyList::create(new Response(200, [], json_encode([
+ $keyList = KeyList::fromResponse(new Response(200, [], json_encode([
Key::ATTRIBUTE_KEYS => static::createKeys(1000),
Key::ATTRIBUTE_NEXT_APPLICATION_KEY_ID => null,
])));
diff --git a/tests/Utils.php b/tests/Utils.php
index c189ecb..e697b08 100644
--- a/tests/Utils.php
+++ b/tests/Utils.php
@@ -2,9 +2,6 @@
namespace tests;
-use Zaxbux\BackblazeB2\Client;
-use Zaxbux\BackblazeB2\Utils as ClientUtils;
-
class Utils {
public static function nowInMilliseconds(): int
{
diff --git a/tests/responses/bucket_not_empty.json b/tests/responses/bucket_not_empty.json
index f828386..8e003d6 100644
--- a/tests/responses/bucket_not_empty.json
+++ b/tests/responses/bucket_not_empty.json
@@ -1,5 +1,5 @@
{
- "code": "cannot_delete_non_empty_bucket",
+ "code": "bad_request",
"message": "Cannot delete non-empty bucket",
"status": 400
}
\ No newline at end of file
diff --git a/tests/responses/get_bucket.json b/tests/responses/get_bucket.json
new file mode 100644
index 0000000..7012cce
--- /dev/null
+++ b/tests/responses/get_bucket.json
@@ -0,0 +1,10 @@
+{
+ "buckets": [
+ {
+ "bucketId": "4a48fe8875c6214145260818",
+ "accountId": "30f20426f0b1",
+ "bucketName" : "Kitten Videos",
+ "bucketType": "allPrivate"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/tests/responses/get_file_info.json b/tests/responses/get_file_info.json
new file mode 100644
index 0000000..61faab9
--- /dev/null
+++ b/tests/responses/get_file_info.json
@@ -0,0 +1,14 @@
+{
+ "accountId": "accountId",
+ "bucketId": "bucketId",
+ "contentLength": 20,
+ "contentSha1": "bc77b0349d325be71ed2ca26d5e68173210e9e18",
+ "contentType": "application/octet-stream",
+ "fileId": "4_z4c2b953461da9c825f260e1b_f1114dbf5bg9707e8_d20160206_m012226_c001_v1111017_t0010",
+ "fileInfo": {
+ "src_last_modified_millis": "1454721688784"
+ },
+ "action": "upload",
+ "uploadTimestamp": "1465983870000",
+ "fileName": "Test file.bin"
+}
\ No newline at end of file
diff --git a/tests/responses/update_file_legal_hold.json b/tests/responses/update_file_legal_hold.json
new file mode 100644
index 0000000..ec1b913
--- /dev/null
+++ b/tests/responses/update_file_legal_hold.json
@@ -0,0 +1,5 @@
+{
+ "fileId": "4_h4a48fe8875c6214145260818_f000000000000472a_d20210515_m032022_c001_v0000123_t0104",
+ "fileName": "typing_test.txt",
+ "legalHold": "on"
+}
\ No newline at end of file
diff --git a/tests/responses/update_file_retention.json b/tests/responses/update_file_retention.json
new file mode 100644
index 0000000..9e21273
--- /dev/null
+++ b/tests/responses/update_file_retention.json
@@ -0,0 +1,8 @@
+{
+ "fileId": "4_h4a48fe8875c6214145260818_f000000000000472a_d20210515_m032022_c001_v0000123_t0104",
+ "fileName": "typing_test.txt",
+ "fileRetention": {
+ "mode": "governance",
+ "retainUntilTimestamp": 1628942493000
+ }
+}
\ No newline at end of file