Skip to content

Commit 47f6283

Browse files
authored
Merge pull request #29 from chrisnharvey/pseudo-directories
Add support for pseudo-directories
2 parents 34c4255 + 623e9d3 commit 47f6283

File tree

2 files changed

+52
-17
lines changed

2 files changed

+52
-17
lines changed

src/SwiftAdapter.php

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
use GuzzleHttp\Psr7\Stream;
1414
use InvalidArgumentException;
1515
use League\Flysystem\Config;
16+
use League\Flysystem\DirectoryAttributes;
1617
use League\Flysystem\FileAttributes;
1718
use League\Flysystem\FilesystemAdapter;
1819
use League\Flysystem\PathPrefixer;
@@ -233,10 +234,13 @@ public function readStream(string $path)
233234
*/
234235
public function listContents(string $path, bool $deep): iterable
235236
{
236-
$location = $this->prefixer->prefixPath($path);
237+
$location = $this->prefixer->prefixDirectoryPath($path);
237238

239+
// Fetch objects with preudo-directory support. See:
240+
// https://docs.openstack.org/swift/latest/api/pseudo-hierarchical-folders-directories.html
238241
$objectList = $this->container->listObjects([
239242
'prefix' => $location,
243+
'delimiter' => '/',
240244
]);
241245

242246
foreach ($objectList as $object) {
@@ -319,25 +323,29 @@ protected function getObject(string $path): StorageObject
319323
return $object;
320324
}
321325

322-
protected function normalizeObject(StorageObject $object): FileAttributes
326+
protected function normalizeObject(StorageObject $object): FileAttributes|DirectoryAttributes
323327
{
324-
$name = $this->prefixer->stripPrefix($object->name);
328+
$name = $this->prefixer->stripDirectoryPrefix($object->name);
325329

326330
if ($object->lastModified instanceof DateTimeInterface) {
327331
$timestamp = $object->lastModified->getTimestamp();
328-
} else {
332+
} elseif (is_string($object->lastModified)) {
329333
$timestamp = strtotime($object->lastModified);
334+
} else {
335+
$timestamp = null;
336+
}
337+
338+
// Check if the object name ends with a slash. This is a pseudo-directory.
339+
if (substr_compare($object->name, '/', -1) === 0) {
340+
return new DirectoryAttributes($name);
330341
}
331342

332343
return new FileAttributes(
333344
$name,
334345
(int) $object->contentLength,
335346
null,
336347
$timestamp,
337-
$object->contentType,
338-
[
339-
'type' => 'file',
340-
]
348+
$object->contentType
341349
);
342350
}
343351

tests/SwiftAdapterTest.php

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,8 @@ public function testDirectoryExists()
125125
$this->container->shouldReceive('listObjects')
126126
->once()
127127
->with([
128-
'prefix' => 'hello',
128+
'prefix' => 'hello/',
129+
'delimiter' => '/',
129130
])
130131
->andReturn($objects);
131132

@@ -138,7 +139,8 @@ public function testDirectoryExists()
138139
$this->container->shouldReceive('listObjects')
139140
->once()
140141
->with([
141-
'prefix' => 'world',
142+
'prefix' => 'world/',
143+
'delimiter' => '/',
142144
])
143145
->andReturn($objects);
144146

@@ -161,7 +163,8 @@ public function testListContents()
161163
$this->container->shouldReceive('listObjects')
162164
->once()
163165
->with([
164-
'prefix' => 'hello',
166+
'prefix' => 'hello/',
167+
'delimiter' => '/',
165168
])
166169
->andReturn($objects);
167170

@@ -172,9 +175,7 @@ public function testListContents()
172175
'mime_type' => 'text/html; charset=UTF-8',
173176
'visibility' => null,
174177
'file_size' => 0,
175-
'extra_metadata' => [
176-
'type' => 'file',
177-
],
178+
'extra_metadata' => [],
178179
];
179180

180181
$contents = $this->adapter->listContents('hello', false);
@@ -188,6 +189,34 @@ public function testListContents()
188189
$this->assertEquals($times, $count);
189190
}
190191

192+
public function testListContentsPseudoDirectory()
193+
{
194+
$object = Mockery::mock(StorageObject::class);
195+
$object->name = 'name/';
196+
$generator = function () use ($object) {
197+
yield $object;
198+
};
199+
$objects = $generator();
200+
$this->container->shouldReceive('listObjects')
201+
->once()
202+
->with([
203+
'prefix' => 'hello/',
204+
'delimiter' => '/',
205+
])
206+
->andReturn($objects);
207+
208+
$expect = [
209+
'path' => 'name',
210+
'type' => 'dir',
211+
'visibility' => null,
212+
'extra_metadata' => [],
213+
'last_modified' => null,
214+
];
215+
216+
$contents = iterator_to_array($this->adapter->listContents('hello', false));
217+
$this->assertEquals($expect, $contents[0]->jsonSerialize());
218+
}
219+
191220
public function testMove()
192221
{
193222
$this->object->shouldReceive('copy')->once()->with([
@@ -358,9 +387,7 @@ public function testMetadataMethods()
358387
'mime_type' => 'text/html; charset=UTF-8',
359388
'visibility' => null,
360389
'file_size' => 0,
361-
'extra_metadata' => [
362-
'type' => 'file',
363-
],
390+
'extra_metadata' => [],
364391
];
365392

366393
foreach ($methods as $method) {

0 commit comments

Comments
 (0)