From 8342580230b0dd033fed5027cd63c25ee83488fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B1=A0=E4=B8=8B=E5=85=8B=E5=BD=A6?= Date: Fri, 27 Aug 2021 18:32:53 +0900 Subject: [PATCH 01/22] update league/flysystem:~2.0 --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 64d4c38..bffca68 100644 --- a/composer.json +++ b/composer.json @@ -9,8 +9,8 @@ } ], "require": { - "php": ">=5.6", - "league/flysystem": "~1.0", + "php": ">=7.2", + "league/flysystem": "~2.0", "sabre/dav": "~4.0|~3.1" }, "require-dev": { From a68426aca30f6c0d1c12688270c683081d84a7e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B1=A0=E4=B8=8B=E5=85=8B=E5=BD=A6?= Date: Fri, 27 Aug 2021 18:46:37 +0900 Subject: [PATCH 02/22] clean up encodePath --- src/WebDAVAdapter.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/WebDAVAdapter.php b/src/WebDAVAdapter.php index c6a8eed..e8c0366 100644 --- a/src/WebDAVAdapter.php +++ b/src/WebDAVAdapter.php @@ -73,13 +73,13 @@ public function __construct(Client $client, $prefix = null, $useStreamedCopy = t * * @return string */ - protected function encodePath($path) + protected function encodePath(string $path): string { - $a = explode('/', $path); - for ($i=0; $i Date: Fri, 27 Aug 2021 18:53:43 +0900 Subject: [PATCH 03/22] use FilesystemAdapter instead of AbstractAdapter --- src/WebDAVAdapter.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/WebDAVAdapter.php b/src/WebDAVAdapter.php index e8c0366..1c0b8de 100644 --- a/src/WebDAVAdapter.php +++ b/src/WebDAVAdapter.php @@ -2,11 +2,11 @@ namespace League\Flysystem\WebDAV; -use League\Flysystem\Adapter\AbstractAdapter; use League\Flysystem\Adapter\Polyfill\NotSupportingVisibilityTrait; use League\Flysystem\Adapter\Polyfill\StreamedCopyTrait; use League\Flysystem\Adapter\Polyfill\StreamedReadingTrait; use League\Flysystem\Config; +use League\Flysystem\FilesystemAdapter; use League\Flysystem\Util; use LogicException; use Sabre\DAV\Client; @@ -15,7 +15,7 @@ use Sabre\DAV\Xml\Property\ResourceType; use Sabre\HTTP\HttpException; -class WebDAVAdapter extends AbstractAdapter +class WebDAVAdapter implements FilesystemAdapter { use StreamedReadingTrait; use StreamedCopyTrait { From 061834969dd8e99836ea965433ddf3bfdf95d5b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B1=A0=E4=B8=8B=E5=85=8B=E5=BD=A6?= Date: Fri, 27 Aug 2021 18:55:13 +0900 Subject: [PATCH 04/22] remove pathPrefix notion --- src/WebDAVAdapter.php | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/src/WebDAVAdapter.php b/src/WebDAVAdapter.php index 1c0b8de..7c78f24 100644 --- a/src/WebDAVAdapter.php +++ b/src/WebDAVAdapter.php @@ -56,13 +56,11 @@ class WebDAVAdapter implements FilesystemAdapter * Constructor. * * @param Client $client - * @param string $prefix * @param bool $useStreamedCopy */ - public function __construct(Client $client, $prefix = null, $useStreamedCopy = true) + public function __construct(Client $client, $useStreamedCopy = true) { $this->client = $client; - $this->setPathPrefix($prefix); $this->setUseStreamedCopy($useStreamedCopy); } @@ -87,7 +85,7 @@ protected function encodePath(string $path): string */ public function getMetadata($path) { - $location = $this->applyPathPrefix($this->encodePath($path)); + $location = $this->encodePath($path); try { $result = $this->client->propFind($location, static::$metadataFields); @@ -117,7 +115,7 @@ public function has($path) */ public function read($path) { - $location = $this->applyPathPrefix($this->encodePath($path)); + $location = $this->encodePath($path); try { $response = $this->client->request('GET', $location); @@ -147,7 +145,7 @@ public function write($path, $contents, Config $config) return false; } - $location = $this->applyPathPrefix($this->encodePath($path)); + $location = $this->encodePath($path); $response = $this->client->request('PUT', $location, $contents); if ($response['statusCode'] >= 400) { @@ -192,8 +190,8 @@ public function updateStream($path, $resource, Config $config) */ public function rename($path, $newpath) { - $location = $this->applyPathPrefix($this->encodePath($path)); - $newLocation = $this->applyPathPrefix($this->encodePath($newpath)); + $location = $this->encodePath($path); + $newLocation = $this->encodePath($newpath); try { $response = $this->client->request('MOVE', '/'.ltrim($location, '/'), null, [ @@ -227,7 +225,7 @@ public function copy($path, $newpath) */ public function delete($path) { - $location = $this->applyPathPrefix($this->encodePath($path)); + $location = $this->encodePath($path); try { $response = $this->client->request('DELETE', $location)['statusCode']; @@ -261,8 +259,7 @@ public function createDir($path, Config $config) } } - $location = $this->applyPathPrefix($encodedPath); - $response = $this->client->request('MKCOL', $location . $this->pathSeparator); + $response = $this->client->request('MKCOL', $encodedPath . '/'); if ($response['statusCode'] !== 201) { return false; @@ -284,14 +281,14 @@ public function deleteDir($dirname) */ public function listContents($directory = '', $recursive = false) { - $location = $this->applyPathPrefix($this->encodePath($directory)); + $location = $this->encodePath($directory); $response = $this->client->propFind($location . '/', static::$metadataFields, 1); array_shift($response); $result = []; foreach ($response as $path => $object) { - $path = $this->removePathPrefix(rawurldecode($path)); + $path = rawurldecode($path); $object = $this->normalizeObject($object, $path); $result[] = $object; @@ -357,8 +354,8 @@ protected function nativeCopy($path, $newPath) return false; } - $location = $this->applyPathPrefix($this->encodePath($path)); - $newLocation = $this->applyPathPrefix($this->encodePath($newPath)); + $location = $this->encodePath($path); + $newLocation = $this->encodePath($newPath); try { $destination = $this->client->getAbsoluteUrl($newLocation); From 032bc830d8574039069a81fe4641e88fe254d30b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B1=A0=E4=B8=8B=E5=85=8B=E5=BD=A6?= Date: Fri, 27 Aug 2021 19:36:10 +0900 Subject: [PATCH 05/22] signature of read() changed --- src/WebDAVAdapter.php | 54 ++++++++++++++++++------------------------- 1 file changed, 23 insertions(+), 31 deletions(-) diff --git a/src/WebDAVAdapter.php b/src/WebDAVAdapter.php index 7c78f24..98f6aeb 100644 --- a/src/WebDAVAdapter.php +++ b/src/WebDAVAdapter.php @@ -7,6 +7,7 @@ use League\Flysystem\Adapter\Polyfill\StreamedReadingTrait; use League\Flysystem\Config; use League\Flysystem\FilesystemAdapter; +use League\Flysystem\UnableToReadFile; use League\Flysystem\Util; use LogicException; use Sabre\DAV\Client; @@ -32,16 +33,6 @@ class WebDAVAdapter implements FilesystemAdapter '{DAV:}resourcetype', ]; - /** - * @var array - */ - protected static $resultMap = [ - '{DAV:}getcontentlength' => 'size', - '{DAV:}getcontenttype' => 'mimetype', - 'content-length' => 'size', - 'content-type' => 'mimetype', - ]; - /** * @var Client */ @@ -113,27 +104,26 @@ public function has($path) /** * {@inheritdoc} */ - public function read($path) + public function read(string $path): string { - $location = $this->encodePath($path); - try { - $response = $this->client->request('GET', $location); - - if ($response['statusCode'] !== 200) { - return false; - } + [ + 'body' => $body, + 'statusCode' => $statusCode, + 'headers' => $headers, + ] = $this->client->request('GET', $this->encodePath($path)); + } catch (ClientException | ClientHttpException $exception) { + throw UnableToReadFile::fromLocation($path, '', $exception); + } - return array_merge([ - 'contents' => $response['body'], - 'timestamp' => strtotime(is_array($response['headers']['last-modified']) - ? current($response['headers']['last-modified']) - : $response['headers']['last-modified']), - 'path' => $path, - ], Util::map($response['headers'], static::$resultMap)); - } catch (Exception $e) { - return false; + if ($statusCode !== 200) { + throw UnableToReadFile::fromLocation($path, "HTTP status code is $statusCode, not 200."); } + + $timestamp = strtotime(current((array)$headers['last-modified'])); + $size = $headers['content-length'] ?? $headers['{DAV:}getcontentlength'] ?? null; + $mimetype = $headers['content-type'] ?? $headers['{DAV:}getcontenttype'] ?? null; + return $body; } /** @@ -387,15 +377,17 @@ protected function normalizeObject(array $object, $path) return ['type' => 'dir', 'path' => trim($path, '/')]; } - $result = Util::map($object, static::$resultMap); + $result = [ + 'type' => 'file', + 'path' => trim($path, '/'), + 'size' => $object['content-length'] ?? $object['{DAV:}getcontentlength'] ?? null, + 'mimetype' => $object['content-type'] ?? $object['{DAV:}getcontenttype'] ?? null, + ]; if (isset($object['{DAV:}getlastmodified'])) { $result['timestamp'] = strtotime($object['{DAV:}getlastmodified']); } - $result['type'] = 'file'; - $result['path'] = trim($path, '/'); - return $result; } From e10761628100b437d2abac4bde56fa007a824887 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B1=A0=E4=B8=8B=E5=85=8B=E5=BD=A6?= Date: Fri, 27 Aug 2021 19:36:31 +0900 Subject: [PATCH 06/22] refactor isDirectory --- src/WebDAVAdapter.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/WebDAVAdapter.php b/src/WebDAVAdapter.php index 98f6aeb..8af0424 100644 --- a/src/WebDAVAdapter.php +++ b/src/WebDAVAdapter.php @@ -397,12 +397,11 @@ protected function normalizeObject(array $object, $path) */ protected function isDirectory(array $object) { - if (isset($object['{DAV:}resourcetype'])) { - /** @var ResourceType $resourceType */ - $resourceType = $object['{DAV:}resourcetype']; + $resourceType = $object['{DAV:}resourcetype'] ?? null; + if ($resourceType instanceof ResourceType) { return $resourceType->is('{DAV:}collection'); } - return isset($object['{DAV:}iscollection']) && $object['{DAV:}iscollection'] === '1'; + return ($object['{DAV:}iscollection'] ?? null) === '1'; } } From 2df0cd79f6e27171c88fdcc9d834568a727f9977 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B1=A0=E4=B8=8B=E5=85=8B=E5=BD=A6?= Date: Fri, 27 Aug 2021 19:37:10 +0900 Subject: [PATCH 07/22] StreamedReadingTrait was removed --- src/WebDAVAdapter.php | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/WebDAVAdapter.php b/src/WebDAVAdapter.php index 8af0424..f876070 100644 --- a/src/WebDAVAdapter.php +++ b/src/WebDAVAdapter.php @@ -4,12 +4,12 @@ use League\Flysystem\Adapter\Polyfill\NotSupportingVisibilityTrait; use League\Flysystem\Adapter\Polyfill\StreamedCopyTrait; -use League\Flysystem\Adapter\Polyfill\StreamedReadingTrait; use League\Flysystem\Config; use League\Flysystem\FilesystemAdapter; use League\Flysystem\UnableToReadFile; use League\Flysystem\Util; use LogicException; +use RuntimeException; use Sabre\DAV\Client; use Sabre\DAV\Exception; use Sabre\DAV\Exception\NotFound; @@ -18,7 +18,6 @@ class WebDAVAdapter implements FilesystemAdapter { - use StreamedReadingTrait; use StreamedCopyTrait { StreamedCopyTrait::copy as streamedCopy; } @@ -126,6 +125,22 @@ public function read(string $path): string return $body; } + /** + * {@inheritdoc} + */ + public function readStream(string $path) + { + $data = $this->read($path); + + $stream = fopen('php://temp', 'w+b'); + if ($stream === false) { + throw new RuntimeException("opening temporary stream failed"); + } + fwrite($stream, $data); + rewind($stream); + return $stream; + } + /** * {@inheritdoc} */ From 30f0931e72aedba3db5d3d02cd48a9811f118394 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B1=A0=E4=B8=8B=E5=85=8B=E5=BD=A6?= Date: Fri, 27 Aug 2021 19:44:42 +0900 Subject: [PATCH 08/22] drop streamedCopy --- src/WebDAVAdapter.php | 35 ++--------------------------------- 1 file changed, 2 insertions(+), 33 deletions(-) diff --git a/src/WebDAVAdapter.php b/src/WebDAVAdapter.php index f876070..f1d7686 100644 --- a/src/WebDAVAdapter.php +++ b/src/WebDAVAdapter.php @@ -3,7 +3,6 @@ namespace League\Flysystem\WebDAV; use League\Flysystem\Adapter\Polyfill\NotSupportingVisibilityTrait; -use League\Flysystem\Adapter\Polyfill\StreamedCopyTrait; use League\Flysystem\Config; use League\Flysystem\FilesystemAdapter; use League\Flysystem\UnableToReadFile; @@ -18,9 +17,6 @@ class WebDAVAdapter implements FilesystemAdapter { - use StreamedCopyTrait { - StreamedCopyTrait::copy as streamedCopy; - } use NotSupportingVisibilityTrait; protected static $metadataFields = [ @@ -37,21 +33,14 @@ class WebDAVAdapter implements FilesystemAdapter */ protected $client; - /** - * @var bool - */ - protected $useStreamedCopy = true; - /** * Constructor. * * @param Client $client - * @param bool $useStreamedCopy */ - public function __construct(Client $client, $useStreamedCopy = true) + public function __construct(Client $client) { $this->client = $client; - $this->setUseStreamedCopy($useStreamedCopy); } /** @@ -218,11 +207,7 @@ public function rename($path, $newpath) */ public function copy($path, $newpath) { - if ($this->useStreamedCopy === true) { - return $this->streamedCopy($path, $newpath); - } else { - return $this->nativeCopy($path, $newpath); - } + return $this->nativeCopy($path, $newpath); } /** @@ -329,22 +314,6 @@ public function getMimetype($path) return $this->getMetadata($path); } - /** - * @return boolean - */ - public function getUseStreamedCopy() - { - return $this->useStreamedCopy; - } - - /** - * @param boolean $useStreamedCopy - */ - public function setUseStreamedCopy($useStreamedCopy) - { - $this->useStreamedCopy = (bool)$useStreamedCopy; - } - /** * Copy a file through WebDav COPY method. * From 1807be70e086256ca73515c00666497fb9c42852 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B1=A0=E4=B8=8B=E5=85=8B=E5=BD=A6?= Date: Fri, 27 Aug 2021 22:01:55 +0900 Subject: [PATCH 09/22] NotSupportingVisibilityTrait was removed --- src/WebDAVAdapter.php | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/WebDAVAdapter.php b/src/WebDAVAdapter.php index f1d7686..7544186 100644 --- a/src/WebDAVAdapter.php +++ b/src/WebDAVAdapter.php @@ -2,10 +2,13 @@ namespace League\Flysystem\WebDAV; -use League\Flysystem\Adapter\Polyfill\NotSupportingVisibilityTrait; use League\Flysystem\Config; +use League\Flysystem\DirectoryAttributes; +use League\Flysystem\FileAttributes; use League\Flysystem\FilesystemAdapter; +use League\Flysystem\StorageAttributes; use League\Flysystem\UnableToReadFile; +use League\Flysystem\UnableToRetrieveMetadata; use League\Flysystem\Util; use LogicException; use RuntimeException; @@ -13,12 +16,11 @@ use Sabre\DAV\Exception; use Sabre\DAV\Exception\NotFound; use Sabre\DAV\Xml\Property\ResourceType; +use Sabre\HTTP\ClientHttpException; use Sabre\HTTP\HttpException; class WebDAVAdapter implements FilesystemAdapter { - use NotSupportingVisibilityTrait; - protected static $metadataFields = [ '{DAV:}displayname', '{DAV:}getcontentlength', @@ -59,6 +61,18 @@ protected function encodePath(string $path): string return implode('/', $parts); } + public function visibility(string $path): FileAttributes + { + $class = __CLASS__; + throw new LogicException("$class does not support visibility. Path: $path"); + } + + public function setVisibility(string $path, string $visibility): void + { + $class = __CLASS__; + throw new LogicException("$class does not support visibility. Path: $path, visibility: $visibility"); + } + /** * {@inheritdoc} */ From 6489fa882bd4674d923ad8df75579213cbf580fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B1=A0=E4=B8=8B=E5=85=8B=E5=BD=A6?= Date: Fri, 27 Aug 2021 23:55:58 +0900 Subject: [PATCH 10/22] upgrade listContents --- src/WebDAVAdapter.php | 40 +++++++++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/src/WebDAVAdapter.php b/src/WebDAVAdapter.php index 7544186..d7052ab 100644 --- a/src/WebDAVAdapter.php +++ b/src/WebDAVAdapter.php @@ -283,25 +283,39 @@ public function deleteDir($dirname) /** * {@inheritdoc} */ - public function listContents($directory = '', $recursive = false) + public function listContents(string $path, bool $deep): iterable { - $location = $this->encodePath($directory); - $response = $this->client->propFind($location . '/', static::$metadataFields, 1); + try { + $response = $this->client->propFind($this->encodePath($path) . '/', static::$metadataFields, 1); + } catch (ClientHttpException $exception) { + throw UnableToRetrieveMetadata::create($path, 'listContents', "HTTP status code is {$exception->getHttpStatus()}, not 200.", $exception); + } array_shift($response); - $result = []; - - foreach ($response as $path => $object) { - $path = rawurldecode($path); - $object = $this->normalizeObject($object, $path); - $result[] = $object; - if ($recursive && $object['type'] === 'dir') { - $result = array_merge($result, $this->listContents($object['path'], true)); + foreach ($response as $rawChildPath => $object) { + $childPath = trim(rawurldecode($rawChildPath), '/'); + if ($this->isDirectory($object)) { + yield DirectoryAttributes::fromArray([ + StorageAttributes::ATTRIBUTE_PATH => $childPath + ]); + if ($deep) { + yield from $this->listContents($childPath, true); + } + } else { + $lastModified = $object['{DAV:}getlastmodified'] ?? null; + $fileSize = $object['content-length'] ?? $object['{DAV:}getcontentlength'] ?? null; + if ($fileSize !== null) { + $fileSize = (int)$fileSize; + } + yield FileAttributes::fromArray([ + StorageAttributes::ATTRIBUTE_PATH => $childPath, + StorageAttributes::ATTRIBUTE_FILE_SIZE => $fileSize, + StorageAttributes::ATTRIBUTE_LAST_MODIFIED => $lastModified !== null ? strtotime($lastModified) : null, + StorageAttributes::ATTRIBUTE_MIME_TYPE => $object['content-type'] ?? $object['{DAV:}getcontenttype'] ?? null, + ]); } } - - return $result; } /** From 6b6aedf3eab41d1884a166aef9343c549e674d6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B1=A0=E4=B8=8B=E5=85=8B=E5=BD=A6?= Date: Fri, 27 Aug 2021 23:13:25 +0900 Subject: [PATCH 11/22] upgrade metadata accessors --- src/WebDAVAdapter.php | 101 ++++++++++++++++++++---------------------- 1 file changed, 47 insertions(+), 54 deletions(-) diff --git a/src/WebDAVAdapter.php b/src/WebDAVAdapter.php index d7052ab..f7a2b8f 100644 --- a/src/WebDAVAdapter.php +++ b/src/WebDAVAdapter.php @@ -6,6 +6,7 @@ use League\Flysystem\DirectoryAttributes; use League\Flysystem\FileAttributes; use League\Flysystem\FilesystemAdapter; +use League\Flysystem\FilesystemException; use League\Flysystem\StorageAttributes; use League\Flysystem\UnableToReadFile; use League\Flysystem\UnableToRetrieveMetadata; @@ -13,11 +14,8 @@ use LogicException; use RuntimeException; use Sabre\DAV\Client; -use Sabre\DAV\Exception; -use Sabre\DAV\Exception\NotFound; use Sabre\DAV\Xml\Property\ResourceType; use Sabre\HTTP\ClientHttpException; -use Sabre\HTTP\HttpException; class WebDAVAdapter implements FilesystemAdapter { @@ -73,34 +71,40 @@ public function setVisibility(string $path, string $visibility): void throw new LogicException("$class does not support visibility. Path: $path, visibility: $visibility"); } - /** - * {@inheritdoc} - */ - public function getMetadata($path) + private function getMetadata(string $path, string $metadataType): ?StorageAttributes { $location = $this->encodePath($path); try { $result = $this->client->propFind($location, static::$metadataFields); + } catch (ClientHttpException $exception) { + throw UnableToRetrieveMetadata::create($path, $metadataType, '', $exception); + } - if (empty($result)) { - return false; - } + if (empty($result)) { + return null; + } - return $this->normalizeObject($result, $path); - } catch (Exception $e) { - return false; - } catch (HttpException $e) { - return false; + $path = trim($path, '/'); + if ($this->isDirectory($result)) { + return DirectoryAttributes::fromArray([StorageAttributes::ATTRIBUTE_PATH => $path]); } + $lastModified = $object['{DAV:}getlastmodified'] ?? null; + return FileAttributes::fromArray([ + StorageAttributes::ATTRIBUTE_PATH => $path, + StorageAttributes::ATTRIBUTE_FILE_SIZE => $object['content-length'] ?? $object['{DAV:}getcontentlength'] ?? null, + StorageAttributes::ATTRIBUTE_LAST_MODIFIED => $lastModified !== null ? strtotime($lastModified) : null, + StorageAttributes::ATTRIBUTE_MIME_TYPE => $object['content-type'] ?? $object['{DAV:}getcontenttype'] ?? null, + ]); } - /** - * {@inheritdoc} - */ - public function has($path) + public function fileExists(string $path): bool { - return $this->getMetadata($path); + try { + return $this->getMetadata($path, 'fileExists') !== null; + } catch (FilesystemException $exception) { + return false; + } } /** @@ -318,28 +322,45 @@ public function listContents(string $path, bool $deep): iterable } } + private static function ensureFileAttributes(?StorageAttributes $metadata, string $path, string $metadataType): FileAttributes + { + if ($metadata === null) { + throw UnableToRetrieveMetadata::create($path, $metadataType, 'file not found'); + } + if ($metadata instanceof DirectoryAttributes) { + throw UnableToRetrieveMetadata::create($path, $metadataType, 'not a file'); + } + if ($metadata instanceof FileAttributes) { + return $metadata; + } + throw new LogicException("never happen"); + } + /** * {@inheritdoc} */ - public function getSize($path) + public function fileSize(string $path): FileAttributes { - return $this->getMetadata($path); + $metadata = $this->getMetadata($path, StorageAttributes::ATTRIBUTE_FILE_SIZE); + return self::ensureFileAttributes($metadata, $path, StorageAttributes::ATTRIBUTE_FILE_SIZE); } /** * {@inheritdoc} */ - public function getTimestamp($path) + public function lastModified(string $path): FileAttributes { - return $this->getMetadata($path); + $metadata = $this->getMetadata($path, StorageAttributes::ATTRIBUTE_LAST_MODIFIED); + return self::ensureFileAttributes($metadata, $path, StorageAttributes::ATTRIBUTE_LAST_MODIFIED); } /** * {@inheritdoc} */ - public function getMimetype($path) + public function mimeType(string $path): FileAttributes { - return $this->getMetadata($path); + $metadata = $this->getMetadata($path, StorageAttributes::ATTRIBUTE_MIME_TYPE); + return self::ensureFileAttributes($metadata, $path, StorageAttributes::ATTRIBUTE_MIME_TYPE); } /** @@ -375,34 +396,6 @@ protected function nativeCopy($path, $newPath) return false; } - /** - * Normalise a WebDAV repsonse object. - * - * @param array $object - * @param string $path - * - * @return array - */ - protected function normalizeObject(array $object, $path) - { - if ($this->isDirectory($object)) { - return ['type' => 'dir', 'path' => trim($path, '/')]; - } - - $result = [ - 'type' => 'file', - 'path' => trim($path, '/'), - 'size' => $object['content-length'] ?? $object['{DAV:}getcontentlength'] ?? null, - 'mimetype' => $object['content-type'] ?? $object['{DAV:}getcontenttype'] ?? null, - ]; - - if (isset($object['{DAV:}getlastmodified'])) { - $result['timestamp'] = strtotime($object['{DAV:}getlastmodified']); - } - - return $result; - } - /** * @param array $object * @return bool From 4ccfa202832e39aad4503700c18ff3ec74e97873 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B1=A0=E4=B8=8B=E5=85=8B=E5=BD=A6?= Date: Fri, 27 Aug 2021 23:34:52 +0900 Subject: [PATCH 12/22] upgrade delete/copy/move --- src/WebDAVAdapter.php | 113 +++++++++++++++++++++--------------------- 1 file changed, 56 insertions(+), 57 deletions(-) diff --git a/src/WebDAVAdapter.php b/src/WebDAVAdapter.php index f7a2b8f..3c6415c 100644 --- a/src/WebDAVAdapter.php +++ b/src/WebDAVAdapter.php @@ -8,6 +8,11 @@ use League\Flysystem\FilesystemAdapter; use League\Flysystem\FilesystemException; use League\Flysystem\StorageAttributes; +use League\Flysystem\UnableToCopyFile; +use League\Flysystem\UnableToCreateDirectory; +use League\Flysystem\UnableToDeleteDirectory; +use League\Flysystem\UnableToDeleteFile; +use League\Flysystem\UnableToMoveFile; use League\Flysystem\UnableToReadFile; use League\Flysystem\UnableToRetrieveMetadata; use League\Flysystem\Util; @@ -200,88 +205,86 @@ public function updateStream($path, $resource, Config $config) /** * {@inheritdoc} */ - public function rename($path, $newpath) + public function move(string $source, string $destination, Config $config): void { - $location = $this->encodePath($path); - $newLocation = $this->encodePath($newpath); + $location = $this->encodePath($source); + $newLocation = $this->encodePath($destination); try { - $response = $this->client->request('MOVE', '/'.ltrim($location, '/'), null, [ - 'Destination' => '/'.ltrim($newLocation, '/'), + ['statusCode' => $statusCode] = $this->client->request('MOVE', '/' . ltrim($location, '/'), null, [ + 'Destination' => '/' . ltrim($newLocation, '/'), ]); - - if ($response['statusCode'] >= 200 && $response['statusCode'] < 300) { - return true; - } - } catch (NotFound $e) { - // Would have returned false here, but would be redundant + } catch (ClientHttpException $exception) { + throw UnableToMoveFile::fromLocationTo($source, $destination, $exception); + } + if ($statusCode < 200 || 300 <= $statusCode) { + throw UnableToMoveFile::fromLocationTo($source, $destination); } - - return false; } /** * {@inheritdoc} */ - public function copy($path, $newpath) + public function copy(string $source, string $destination, Config $config): void { - return $this->nativeCopy($path, $newpath); + $this->nativeCopy($source, $destination, $config); } /** - * {@inheritdoc} + * @param string $path + * @param string|UnableToDeleteFile|UnableToDeleteDirectory $exceptionToThrow */ - public function delete($path) + public function deleteImpl(string $path, string $exceptionToThrow): void { $location = $this->encodePath($path); try { - $response = $this->client->request('DELETE', $location)['statusCode']; - + ['statusCode' => $statusCode] = $this->client->request('DELETE', $location); + } catch (ClientHttpException $exception) { + throw $exceptionToThrow::atLocation($path, '', $exception); + } - return $response >= 200 && $response < 300; - } catch (NotFound $e) { - return false; + if ($statusCode < 200 || 300 <= $statusCode) { + throw $exceptionToThrow::atLocation($path); } } + public function delete(string $path): void + { + $this->deleteImpl($path, UnableToDeleteFile::class); + } + /** * {@inheritdoc} */ - public function createDir($path, Config $config) + public function createDirectory(string $path, Config $config): void { $encodedPath = $this->encodePath($path); $path = trim($path, '/'); - $result = compact('path') + ['type' => 'dir']; - - if (Util::normalizeDirname($path) === '' || $this->has($path)) { - return $result; + if ($path === '.' || $path === '' || $this->fileExists($path)) { + return; } $directories = explode('/', $path); if (count($directories) > 1) { $parentDirectories = array_splice($directories, 0, count($directories) - 1); - if (!$this->createDir(implode('/', $parentDirectories), $config)) { - return false; - } + $this->createDirectory(implode('/', $parentDirectories), $config); } - $response = $this->client->request('MKCOL', $encodedPath . '/'); + ['statusCode' => $statusCode] = $this->client->request('MKCOL', $encodedPath . '/'); - if ($response['statusCode'] !== 201) { - return false; + if ($statusCode !== 201) { + throw UnableToCreateDirectory::atLocation($path); } - - return $result; } /** * {@inheritdoc} */ - public function deleteDir($dirname) + public function deleteDirectory(string $path): void { - return $this->delete($dirname); + $this->deleteImpl($path, UnableToDeleteDirectory::class); } /** @@ -366,34 +369,30 @@ public function mimeType(string $path): FileAttributes /** * Copy a file through WebDav COPY method. * - * @param string $path - * @param string $newPath - * - * @return bool + * @param string $source + * @param string $destination + * @throws FilesystemException */ - protected function nativeCopy($path, $newPath) + protected function nativeCopy(string $source, string $destination, Config $config): void { - if (!$this->createDir(Util::dirname($newPath), new Config())) { - return false; + $directory = dirname($destination); + if ($directory === '.') { + $directory = ''; } + $this->createDirectory($directory, $config); - $location = $this->encodePath($path); - $newLocation = $this->encodePath($newPath); - + $location = $this->encodePath($source); try { - $destination = $this->client->getAbsoluteUrl($newLocation); - $response = $this->client->request('COPY', '/'.ltrim($location, '/'), null, [ - 'Destination' => $destination, + ['statusCode' => $statusCode] = $this->client->request('COPY', '/' . ltrim($location, '/'), null, [ + 'Destination' => $this->client->getAbsoluteUrl($this->encodePath($destination)), ]); - - if ($response['statusCode'] >= 200 && $response['statusCode'] < 300) { - return true; - } - } catch (NotFound $e) { - // Would have returned false here, but would be redundant + } catch (ClientHttpException $exception) { + throw UnableToCopyFile::fromLocationTo($source, $destination, $exception); } - return false; + if ($statusCode < 200 || 300 <= $statusCode) { + throw UnableToCopyFile::fromLocationTo($source, $destination); + } } /** From f26c7badb66ebe41ccfef7e823afd4316f94689f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B1=A0=E4=B8=8B=E5=85=8B=E5=BD=A6?= Date: Fri, 27 Aug 2021 23:48:53 +0900 Subject: [PATCH 13/22] upgrade write --- src/WebDAVAdapter.php | 49 +++++++++++++++++++------------------------ 1 file changed, 21 insertions(+), 28 deletions(-) diff --git a/src/WebDAVAdapter.php b/src/WebDAVAdapter.php index 3c6415c..18ab810 100644 --- a/src/WebDAVAdapter.php +++ b/src/WebDAVAdapter.php @@ -15,7 +15,7 @@ use League\Flysystem\UnableToMoveFile; use League\Flysystem\UnableToReadFile; use League\Flysystem\UnableToRetrieveMetadata; -use League\Flysystem\Util; +use League\Flysystem\UnableToWriteFile; use LogicException; use RuntimeException; use Sabre\DAV\Client; @@ -154,52 +154,45 @@ public function readStream(string $path) } /** - * {@inheritdoc} + * @param string $path + * @param string|resource $contents + * @param Config $config + * @throws FilesystemException */ - public function write($path, $contents, Config $config) + protected function writeImpl(string $path, $contents, Config $config): void { - if (!$this->createDir(Util::dirname($path), $config)) { - return false; + if ($config->get(StorageAttributes::ATTRIBUTE_VISIBILITY)) { + throw new LogicException(__CLASS__.' does not support visibility settings.'); } - $location = $this->encodePath($path); - $response = $this->client->request('PUT', $location, $contents); - - if ($response['statusCode'] >= 400) { - return false; + $directory = dirname($path); + if ($directory === '.') { + $directory = ''; } + $this->createDirectory($directory, $config); - $result = compact('path', 'contents'); - - if ($config->get('visibility')) { - throw new LogicException(__CLASS__.' does not support visibility settings.'); + $location = $this->encodePath($path); + try { + $this->client->request('PUT', $location, $contents); + } catch (ClientHttpException $exception) { + throw UnableToWriteFile::atLocation($path, '', $exception); } - - return $result; - } - - /** - * {@inheritdoc} - */ - public function writeStream($path, $resource, Config $config) - { - return $this->write($path, $resource, $config); } /** * {@inheritdoc} */ - public function update($path, $contents, Config $config) + public function write(string $path, string $contents, Config $config): void { - return $this->write($path, $contents, $config); + $this->writeImpl($path, $contents, $config); } /** * {@inheritdoc} */ - public function updateStream($path, $resource, Config $config) + public function writeStream(string $path, $contents, Config $config): void { - return $this->update($path, $resource, $config); + $this->writeImpl($path, $contents, $config); } /** From 5af7427e8d23ab48ea834f9ac0a81bd3acf72ae1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B1=A0=E4=B8=8B=E5=85=8B=E5=BD=A6?= Date: Fri, 27 Aug 2021 23:49:22 +0900 Subject: [PATCH 14/22] make the client throw exceptions --- src/WebDAVAdapter.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/WebDAVAdapter.php b/src/WebDAVAdapter.php index 18ab810..ee1ba50 100644 --- a/src/WebDAVAdapter.php +++ b/src/WebDAVAdapter.php @@ -45,6 +45,7 @@ class WebDAVAdapter implements FilesystemAdapter */ public function __construct(Client $client) { + $client->setThrowExceptions(true); $this->client = $client; } From 4c3da1954ca667fad15a2334d46b61c61ed57aaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B1=A0=E4=B8=8B=E5=85=8B=E5=BD=A6?= Date: Fri, 27 Aug 2021 23:59:18 +0900 Subject: [PATCH 15/22] catch ClientException --- src/WebDAVAdapter.php | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/WebDAVAdapter.php b/src/WebDAVAdapter.php index ee1ba50..05162e9 100644 --- a/src/WebDAVAdapter.php +++ b/src/WebDAVAdapter.php @@ -20,6 +20,7 @@ use RuntimeException; use Sabre\DAV\Client; use Sabre\DAV\Xml\Property\ResourceType; +use Sabre\HTTP\ClientException; use Sabre\HTTP\ClientHttpException; class WebDAVAdapter implements FilesystemAdapter @@ -83,7 +84,7 @@ private function getMetadata(string $path, string $metadataType): ?StorageAttrib try { $result = $this->client->propFind($location, static::$metadataFields); - } catch (ClientHttpException $exception) { + } catch (ClientException | ClientHttpException $exception) { throw UnableToRetrieveMetadata::create($path, $metadataType, '', $exception); } @@ -175,7 +176,7 @@ protected function writeImpl(string $path, $contents, Config $config): void $location = $this->encodePath($path); try { $this->client->request('PUT', $location, $contents); - } catch (ClientHttpException $exception) { + } catch (ClientException | ClientHttpException $exception) { throw UnableToWriteFile::atLocation($path, '', $exception); } } @@ -208,7 +209,7 @@ public function move(string $source, string $destination, Config $config): void ['statusCode' => $statusCode] = $this->client->request('MOVE', '/' . ltrim($location, '/'), null, [ 'Destination' => '/' . ltrim($newLocation, '/'), ]); - } catch (ClientHttpException $exception) { + } catch (ClientException | ClientHttpException $exception) { throw UnableToMoveFile::fromLocationTo($source, $destination, $exception); } if ($statusCode < 200 || 300 <= $statusCode) { @@ -234,7 +235,7 @@ public function deleteImpl(string $path, string $exceptionToThrow): void try { ['statusCode' => $statusCode] = $this->client->request('DELETE', $location); - } catch (ClientHttpException $exception) { + } catch (ClientException | ClientHttpException $exception) { throw $exceptionToThrow::atLocation($path, '', $exception); } @@ -288,8 +289,8 @@ public function listContents(string $path, bool $deep): iterable { try { $response = $this->client->propFind($this->encodePath($path) . '/', static::$metadataFields, 1); - } catch (ClientHttpException $exception) { - throw UnableToRetrieveMetadata::create($path, 'listContents', "HTTP status code is {$exception->getHttpStatus()}, not 200.", $exception); + } catch (ClientException | ClientHttpException $exception) { + throw UnableToRetrieveMetadata::create($path, 'listContents', '', $exception); } array_shift($response); @@ -380,7 +381,7 @@ protected function nativeCopy(string $source, string $destination, Config $confi ['statusCode' => $statusCode] = $this->client->request('COPY', '/' . ltrim($location, '/'), null, [ 'Destination' => $this->client->getAbsoluteUrl($this->encodePath($destination)), ]); - } catch (ClientHttpException $exception) { + } catch (ClientException | ClientHttpException $exception) { throw UnableToCopyFile::fromLocationTo($source, $destination, $exception); } From 200e249492b380bd08389ffcf81f1c0a4d925b06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B1=A0=E4=B8=8B=E5=85=8B=E5=BD=A6?= Date: Sat, 28 Aug 2021 09:33:04 +0900 Subject: [PATCH 16/22] upgrade phpunit to 8 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index bffca68..9fac7fb 100644 --- a/composer.json +++ b/composer.json @@ -14,7 +14,7 @@ "sabre/dav": "~4.0|~3.1" }, "require-dev": { - "phpunit/phpunit": "~4.8", + "phpunit/phpunit": "~8.5", "mockery/mockery": "~1.2" }, "autoload": { From 35a03f749cf7436eeabbab88a0e805f14de647c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B1=A0=E4=B8=8B=E5=85=8B=E5=BD=A6?= Date: Sat, 28 Aug 2021 09:21:14 +0900 Subject: [PATCH 17/22] fix tests --- tests/WebDAVTests.php | 204 ++++++++++++++++++++---------------------- 1 file changed, 99 insertions(+), 105 deletions(-) diff --git a/tests/WebDAVTests.php b/tests/WebDAVTests.php index 147e03c..7effbfb 100644 --- a/tests/WebDAVTests.php +++ b/tests/WebDAVTests.php @@ -2,45 +2,50 @@ use League\Flysystem\Config; use League\Flysystem\Filesystem; +use League\Flysystem\UnableToCreateDirectory; +use League\Flysystem\UnableToDeleteDirectory; +use League\Flysystem\UnableToMoveFile; +use League\Flysystem\UnableToReadFile; +use League\Flysystem\UnableToWriteFile; use League\Flysystem\WebDAV\WebDAVAdapter; use PHPUnit\Framework\TestCase; +use Sabre\HTTP\Response; class WebDAVTests extends TestCase { use Mockery\Adapter\Phpunit\MockeryPHPUnitIntegration; + /** + * @return \Mockery\LegacyMockInterface|\Mockery\MockInterface|\Sabre\DAV\Client + */ protected function getClient() { - return Mockery::mock('Sabre\DAV\Client'); + $mock = Mockery::mock(Sabre\DAV\Client::class); + $mock->shouldReceive('setThrowExceptions')->once(); + return $mock; + } + + protected function newClientHttpException(int $httpStatus, array $headers = [], ?string $body = null) + { + return new Sabre\HTTP\ClientHttpException(new Response($httpStatus, $headers, $body)); } - public function testHas() + public function testFileExists() { $mock = $this->getClient(); $mock->shouldReceive('propFind')->once()->andReturn([ '{DAV:}getcontentlength' => 20, ]); $adapter = new Filesystem(new WebDAVAdapter($mock)); - $this->assertTrue($adapter->has('something')); + $this->assertTrue($adapter->fileExists('something')); } - /** - * @dataProvider provideExceptionsForHasFail - */ - public function testHasFail($exceptionClass) + public function testHasFail() { $mock = $this->getClient(); - $mock->shouldReceive('propFind')->once()->andThrow($exceptionClass); + $mock->shouldReceive('propFind')->once()->andThrow($this->newClientHttpException(404)); $adapter = new WebDAVAdapter($mock); - $this->assertFalse($adapter->has('something')); - } - - public function provideExceptionsForHasFail() - { - return [ - [Mockery::mock('Sabre\DAV\Exception\NotFound')], - [Mockery::mock('Sabre\HTTP\ClientHttpException')], - ]; + $this->assertFalse($adapter->fileExists('something')); } public function testWrite() @@ -50,18 +55,16 @@ public function testWrite() 'statusCode' => 200, ]); $adapter = new WebDAVAdapter($mock); - $this->assertInternalType('array', $adapter->write('something', 'something', new Config())); + $adapter->write('something', 'something', new Config()); } public function testWriteFail() { $mock = $this->getClient(); - $mock->shouldReceive('request')->with('PUT', 'something', 'something')->once()->andReturn([ - 'statusCode' => 500, - ]); + $mock->shouldReceive('request')->with('PUT', 'something', 'something')->once()->andThrow($this->newClientHttpException(500)); $adapter = new WebDAVAdapter($mock); - $result = $adapter->write('something', 'something', new Config()); - $this->assertFalse($result); + $this->expectException(UnableToWriteFile::class); + $adapter->write('something', 'something', new Config()); } public function testWriteStream() @@ -74,7 +77,7 @@ public function testWriteStream() $tmp = $this->getLargeTmpStream(); - $this->assertInternalType('array', $adapter->writeStream('something', $tmp, new Config())); + $adapter->writeStream('something', $tmp, new Config()); if (is_resource($tmp)) { fclose($tmp); @@ -110,29 +113,15 @@ protected function getMemoryLimit() return $limit; } - public function testUpdate() - { - $mock = $this->getClient(); - $mock->shouldReceive('request') - ->once() - ->andReturn(['statusCode' => 201]); - $adapter = new WebDAVAdapter($mock); - $this->assertInternalType('array', $adapter->update('something', 'something', new Config())); - } - - /** - * @expectedException LogicException - */ public function testWriteVisibility() { $mock = $this->getClient(); - $mock->shouldReceive('request')->once()->andReturn([ - 'statusCode' => 200, - ]); + $mock->shouldReceive('request')->never(); $adapter = new WebDAVAdapter($mock); - $this->assertInternalType('array', $adapter->write('something', 'something', new Config([ + $this->expectException(LogicException::class); + $adapter->write('something', 'something', new Config([ 'visibility' => 'private', - ]))); + ])); } public function testReadStream() @@ -145,9 +134,16 @@ public function testReadStream() 'last-modified' => date('Y-m-d H:i:s'), ], ]); - $adapter = new WebDAVAdapter($mock, 'bucketname', 'prefix'); - $result = $adapter->readStream('file.txt'); - $this->assertInternalType('resource', $result['stream']); + $adapter = new WebDAVAdapter($mock); + $resource = $adapter->readStream('file.txt'); + $this->assertIsResource($resource); + $result = ""; + while (!feof($resource)) { + $read = fread($resource, 100); + $this->assertIsString($read); + $result .= $read; + } + $this->assertSame('contents', $result); } public function testRename() @@ -156,9 +152,8 @@ public function testRename() $mock->shouldReceive('request')->once()->andReturn([ 'statusCode' => 200, ]); - $adapter = new WebDAVAdapter($mock, 'bucketname'); - $result = $adapter->rename('old', 'new'); - $this->assertTrue($result); + $adapter = new WebDAVAdapter($mock); + $adapter->move('old', 'new', new Config()); } public function testRenameFail() @@ -167,18 +162,18 @@ public function testRenameFail() $mock->shouldReceive('request')->once()->andReturn([ 'statusCode' => 404, ]); - $adapter = new WebDAVAdapter($mock, 'bucketname'); - $result = $adapter->rename('old', 'new'); - $this->assertFalse($result); + $adapter = new WebDAVAdapter($mock); + $this->expectException(UnableToMoveFile::class); + $adapter->move('old', 'new', new Config()); } public function testRenameFailException() { $mock = $this->getClient(); - $mock->shouldReceive('request')->once()->andThrow('Sabre\DAV\Exception\NotFound'); - $adapter = new WebDAVAdapter($mock, 'bucketname'); - $result = $adapter->rename('old', 'new'); - $this->assertFalse($result); + $mock->shouldReceive('request')->once()->andThrow($this->newClientHttpException(500)); + $adapter = new WebDAVAdapter($mock); + $this->expectException(UnableToMoveFile::class); + $adapter->move('old', 'new', new Config()); } public function testDeleteDir() @@ -186,17 +181,16 @@ public function testDeleteDir() $mock = $this->getClient(); $mock->shouldReceive('request')->with('DELETE', 'some/dirname')->once()->andReturn(['statusCode' => 200]); $adapter = new WebDAVAdapter($mock); - $result = $adapter->deleteDir('some/dirname'); - $this->assertTrue($result); + $adapter->deleteDirectory('some/dirname'); } public function testDeleteDirFailNotFound() { $mock = $this->getClient(); - $mock->shouldReceive('request')->with('DELETE', 'some/dirname')->once()->andThrow('Sabre\DAV\Exception\NotFound'); + $mock->shouldReceive('request')->with('DELETE', 'some/dirname')->once()->andThrow($this->newClientHttpException(404)); $adapter = new WebDAVAdapter($mock); - $result = $adapter->deleteDir('some/dirname'); - $this->assertFalse($result); + $this->expectException(UnableToDeleteDirectory::class); + $adapter->deleteDirectory('some/dirname'); } public function testDeleteDirFailNot200Status() @@ -204,8 +198,8 @@ public function testDeleteDirFailNot200Status() $mock = $this->getClient(); $mock->shouldReceive('request')->with('DELETE', 'some/dirname')->once()->andReturn(['statusCode' => 403]); $adapter = new WebDAVAdapter($mock); - $result = $adapter->deleteDir('some/dirname'); - $this->assertFalse($result); + $this->expectException(UnableToDeleteDirectory::class); + $adapter->deleteDirectory('some/dirname'); } public function testListContents() @@ -231,9 +225,10 @@ public function testListContents() ], ]; $mock->shouldReceive('propFind')->twice()->andReturn($first, $second); - $adapter = new WebDAVAdapter($mock, 'bucketname'); + $adapter = new WebDAVAdapter($mock); $listing = $adapter->listContents('', true); - $this->assertInternalType('array', $listing); + $this->assertInstanceOf(Generator::class, $listing); + iterator_to_array($listing); } public function testListContentsWithPlusInName() @@ -248,11 +243,12 @@ public function testListContentsWithPlusInName() ]; $mock->shouldReceive('propFind')->once()->andReturn($first); - $adapter = new WebDAVAdapter($mock, 'bucketname'); + $adapter = new WebDAVAdapter($mock); $listing = $adapter->listContents('', false); - $this->assertInternalType('array', $listing); + $this->assertInstanceOf(Generator::class, $listing); + $listing = iterator_to_array($listing); $this->assertCount(1, $listing); - $this->assertEquals('dirname+something', $listing[0]['path']); + $this->assertEquals('bucketname/dirname+something', $listing[0]['path']); } public function testListContentsWithUrlEncodedSpaceInName() @@ -267,29 +263,31 @@ public function testListContentsWithUrlEncodedSpaceInName() ]; $mock->shouldReceive('propFind')->once()->andReturn($first); - $adapter = new WebDAVAdapter($mock, '/My Library'); + $adapter = new WebDAVAdapter($mock); $listing = $adapter->listContents('', false); - $this->assertInternalType('array', $listing); + $this->assertInstanceOf(Generator::class, $listing); + $listing = iterator_to_array($listing); $this->assertCount(1, $listing); - $this->assertEquals('New Record 1.mp3', $listing[0]['path']); - $this->assertEquals('file', $listing[0]['type']); - $this->assertEquals('8223370', $listing[0]['size']); + $attributes = $listing[0]; + $this->assertInstanceOf(\League\Flysystem\FileAttributes::class, $attributes); + $this->assertEquals('My Library/New Record 1.mp3', $attributes->path()); + $this->assertEquals('file', $attributes->type()); + $this->assertEquals(8223370, $attributes->fileSize()); } - public function methodProvider() + public function methodProvider(): array { return [ - ['getMetadata'], - ['getTimestamp'], - ['getMimetype'], - ['getSize'], + ['lastModified'], + ['mimeType'], + ['fileSize'], ]; } /** * @dataProvider methodProvider */ - public function testMetaMethods($method) + public function testMetaMethods(string $method) { $mock = $this->getClient(); $mock->shouldReceive('propFind')->once()->andReturn([ @@ -300,7 +298,7 @@ public function testMetaMethods($method) ]); $adapter = new WebDAVAdapter($mock); $result = $adapter->{$method}('object.ext'); - $this->assertInternalType('array', $result); + $this->assertInstanceOf(\League\Flysystem\FileAttributes::class, $result); } public function testCreateDir() @@ -310,7 +308,7 @@ public function testCreateDir() $mock->shouldReceive('propFind') ->once() - ->andThrow(new \Sabre\DAV\Exception('Not found')); + ->andThrow($this->newClientHttpException(404)); $mock->shouldReceive('request') ->once() @@ -320,8 +318,7 @@ public function testCreateDir() ]); $adapter = new WebDAVAdapter($mock); - $result = $adapter->createDir('dirname', new Config()); - $this->assertInternalType('array', $result); + $adapter->createDirectory('dirname', new Config()); } public function testCreateDirRecursive() @@ -331,7 +328,7 @@ public function testCreateDirRecursive() $mock->shouldReceive('propFind') ->times(2) - ->andThrow(new \Sabre\DAV\Exception('Not found')); + ->andThrow($this->newClientHttpException(404)); $mock->shouldReceive('request') ->once() @@ -348,8 +345,7 @@ public function testCreateDirRecursive() ]); $adapter = new WebDAVAdapter($mock); - $result = $adapter->createDir('dirname/subdirname', new Config()); - $this->assertInternalType('array', $result); + $adapter->createDirectory('dirname/subdirname', new Config()); } public function testCreateDirIfExists() @@ -370,8 +366,7 @@ public function testCreateDirIfExists() ->never(); $adapter = new WebDAVAdapter($mock); - $result = $adapter->createDir('dirname', new Config()); - $this->assertInternalType('array', $result); + $adapter->createDirectory('dirname', new Config()); } public function testCreateDirFail() @@ -381,7 +376,7 @@ public function testCreateDirFail() $mock->shouldReceive('propFind') ->once() - ->andThrow(new \Sabre\DAV\Exception('Not found')); + ->andThrow($this->newClientHttpException(404)); $mock->shouldReceive('request') ->once() @@ -391,8 +386,8 @@ public function testCreateDirFail() ]); $adapter = new WebDAVAdapter($mock); - $result = $adapter->createDir('dirname', new Config()); - $this->assertFalse($result); + $this->expectException(UnableToCreateDirectory::class); + $adapter->createDirectory('dirname', new Config()); } public function testRead() @@ -405,9 +400,9 @@ public function testRead() 'last-modified' => [date('Y-m-d H:i:s')], ], ]); - $adapter = new WebDAVAdapter($mock, 'bucketname', 'prefix'); + $adapter = new WebDAVAdapter($mock); $result = $adapter->read('file.txt'); - $this->assertInternalType('array', $result); + $this->assertSame('contents', $result); } public function testReadFail() @@ -420,9 +415,9 @@ public function testReadFail() 'last-modified' => [date('Y-m-d H:i:s')], ], ]); - $adapter = new WebDAVAdapter($mock, 'bucketname', 'prefix'); - $result = $adapter->read('file.txt'); - $this->assertFalse($result); + $adapter = new WebDAVAdapter($mock); + $this->expectException(UnableToReadFile::class); + $adapter->read('file.txt'); } public function testReadStreamFail() @@ -435,18 +430,18 @@ public function testReadStreamFail() 'last-modified' => [date('Y-m-d H:i:s')], ], ]); - $adapter = new WebDAVAdapter($mock, 'bucketname', 'prefix'); - $result = $adapter->readStream('file.txt'); - $this->assertFalse($result); + $adapter = new WebDAVAdapter($mock); + $this->expectException(UnableToReadFile::class); + $adapter->readStream('file.txt'); } public function testReadException() { $mock = $this->getClient(); - $mock->shouldReceive('request')->andThrow('Sabre\DAV\Exception\NotFound'); - $adapter = new WebDAVAdapter($mock, 'bucketname', 'prefix'); - $result = $adapter->read('file.txt'); - $this->assertFalse($result); + $mock->shouldReceive('request')->andThrow($this->newClientHttpException(404)); + $adapter = new WebDAVAdapter($mock); + $this->expectException(UnableToReadFile::class); + $adapter->read('file.txt'); } public function testNativeCopy() @@ -460,8 +455,7 @@ public function testNativeCopy() 'statusCode' => 201 ]); - $adapter = new WebDAVAdapter($clientMock, 'prefix', false); - $result = $adapter->copy('file.txt', 'newFile.txt'); - $this->assertTrue($result); + $adapter = new WebDAVAdapter($clientMock); + $adapter->copy('file.txt', 'newFile.txt', new Config()); } } From 4c50ecc948f24d7e4ba5518a74c91e551b2e687b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B1=A0=E4=B8=8B=E5=85=8B=E5=BD=A6?= Date: Sat, 28 Aug 2021 09:41:42 +0900 Subject: [PATCH 18/22] drop support for php<7.2 --- .travis.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9748397..26a2459 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,9 +5,6 @@ services: language: php php: - - 5.6 - - 7.0 - - 7.1 - 7.2 - 7.3 - 7.4 From dee10830179503890cdb5f729de184ec121b29a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B1=A0=E4=B8=8B=E5=85=8B=E5=BD=A6?= Date: Fri, 27 Aug 2021 16:30:52 +0900 Subject: [PATCH 19/22] use phpdoc return type --- tests/WebDAVTests.php | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/tests/WebDAVTests.php b/tests/WebDAVTests.php index 7effbfb..b786ea8 100644 --- a/tests/WebDAVTests.php +++ b/tests/WebDAVTests.php @@ -9,6 +9,7 @@ use League\Flysystem\UnableToWriteFile; use League\Flysystem\WebDAV\WebDAVAdapter; use PHPUnit\Framework\TestCase; +use Sabre\DAV\Client; use Sabre\HTTP\Response; class WebDAVTests extends TestCase @@ -16,7 +17,7 @@ class WebDAVTests extends TestCase use Mockery\Adapter\Phpunit\MockeryPHPUnitIntegration; /** - * @return \Mockery\LegacyMockInterface|\Mockery\MockInterface|\Sabre\DAV\Client + * @return Mockery\LegacyMockInterface|Mockery\MockInterface|Client */ protected function getClient() { @@ -303,7 +304,6 @@ public function testMetaMethods(string $method) public function testCreateDir() { - /** @var Sabre\DAV\Client|Mockery\Mock $mock */ $mock = $this->getClient(); $mock->shouldReceive('propFind') @@ -323,7 +323,6 @@ public function testCreateDir() public function testCreateDirRecursive() { - /** @var Sabre\DAV\Client|Mockery\Mock $mock */ $mock = $this->getClient(); $mock->shouldReceive('propFind') @@ -350,7 +349,6 @@ public function testCreateDirRecursive() public function testCreateDirIfExists() { - /** @var Sabre\DAV\Client|Mockery\Mock $mock */ $mock = $this->getClient(); $mock->shouldReceive('propFind') @@ -371,7 +369,6 @@ public function testCreateDirIfExists() public function testCreateDirFail() { - /** @var Sabre\DAV\Client|Mockery\Mock $mock */ $mock = $this->getClient(); $mock->shouldReceive('propFind') @@ -446,7 +443,6 @@ public function testReadException() public function testNativeCopy() { - /** @var Sabre\DAV\Client|Mockery\Mock $clientMock */ $clientMock = $this->getClient(); $clientMock->shouldReceive('getAbsoluteUrl')->andReturn('http://webdav.local/prefix/newFile.txt'); From 3c3a76d5a2e73928863372a9e5899f9b33bd354f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B1=A0=E4=B8=8B=E5=85=8B=E5=BD=A6?= Date: Fri, 27 Aug 2021 16:35:49 +0900 Subject: [PATCH 20/22] resolve warnings --- tests/WebDAVTests.php | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/tests/WebDAVTests.php b/tests/WebDAVTests.php index b786ea8..e9f52f8 100644 --- a/tests/WebDAVTests.php +++ b/tests/WebDAVTests.php @@ -87,7 +87,7 @@ public function testWriteStream() protected function getLargeTmpStream() { - $size = intval($this->getMemoryLimit() * 1.5); + $size = (int)($this->getMemoryLimit() * 1.5); $tmp = tmpfile(); fseek($tmp, $size); fprintf($tmp, 'a'); @@ -106,12 +106,10 @@ protected function getMemoryLimit() ]; if (!preg_match("/^(\d+)([KMG]?)$/i", ini_get('memory_limit'), $match)) { - throw new Exception('invalid memory_limit?'); + throw new UnexpectedValueException('invalid memory_limit?'); } - $limit = $match[1] * pow(1024, $unit_factor[strtoupper($match[2])]); - - return $limit; + return $match[1] * (1024 ** $unit_factor[strtoupper($match[2])]); } public function testWriteVisibility() From 73ca24bcdcac10ef977af61530720c9df9e7e4c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B1=A0=E4=B8=8B=E5=85=8B=E5=BD=A6?= Date: Sat, 28 Aug 2021 12:10:55 +0900 Subject: [PATCH 21/22] remove unused variables --- src/WebDAVAdapter.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/WebDAVAdapter.php b/src/WebDAVAdapter.php index 05162e9..6b7667f 100644 --- a/src/WebDAVAdapter.php +++ b/src/WebDAVAdapter.php @@ -133,9 +133,6 @@ public function read(string $path): string throw UnableToReadFile::fromLocation($path, "HTTP status code is $statusCode, not 200."); } - $timestamp = strtotime(current((array)$headers['last-modified'])); - $size = $headers['content-length'] ?? $headers['{DAV:}getcontentlength'] ?? null; - $mimetype = $headers['content-type'] ?? $headers['{DAV:}getcontenttype'] ?? null; return $body; } From 0688d8f61ee64d7d6f9728360ca9dd8f7b400d76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B1=A0=E4=B8=8B=E5=85=8B=E5=BD=A6?= Date: Sat, 28 Aug 2021 12:31:47 +0900 Subject: [PATCH 22/22] add php 8.0 to travis yaml --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 26a2459..6ac7558 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,6 +8,7 @@ php: - 7.2 - 7.3 - 7.4 + - 8.0 install: - travis_retry composer install --no-interaction --prefer-source