├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── changelog.md ├── composer.json ├── phpunit.php ├── phpunit.xml.dist ├── src └── PhpcrAdapter.php └── tests └── PhpcrAdapterTest.php /.gitignore: -------------------------------------------------------------------------------- 1 | /composer.lock 2 | /vendor/ 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - 5.4 5 | - 5.5 6 | - 5.6 7 | 8 | cache: 9 | directories: 10 | - $HOME/.composer/cache 11 | 12 | install: 13 | - travis_retry composer install --no-interaction --prefer-dist 14 | 15 | script: 16 | - bash -c 'if [ "$TRAVIS_PHP_VERSION" == "hhvm" ]; then bin/phpunit; fi;' 17 | - bash -c 'if [ "$TRAVIS_PHP_VERSION" != "hhvm" ]; then bin/phpunit --coverage-text --coverage-clover coverage.xml; fi;' 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 David Buchmann 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is furnished 8 | to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Flysystem Adapter for the PHP Content Repository PHPCR 2 | 3 | [![Build Status](https://img.shields.io/travis/thephpleague/flysystem-phpcr/master.svg?style=flat-square)](https://travis-ci.org/thephpleague/flysystem-phpcr) 4 | [![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE) 5 | [![Packagist Version](https://img.shields.io/packagist/v/league/flysystem-phpcr.svg?style=flat-square)](https://packagist.org/packages/league/flysystem-phpcr) 6 | [![Total Downloads](https://img.shields.io/packagist/dt/league/flysystem-phpcr.svg?style=flat-square)](https://packagist.org/packages/league/flysystem-phpcr) 7 | 8 | ## Documentation 9 | 10 | See https://flysystem.thephpleague.com/docs/adapter/phpcr/ 11 | -------------------------------------------------------------------------------- /changelog.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## 1.1.0 - 2018-06-04 4 | 5 | ### Added 6 | 7 | * File timestamp can be set to any time through the configuration 8 | 9 | ### Fixed 10 | 11 | * Return encoding in metadata after file creation 12 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "league/flysystem-phpcr", 3 | "description": "Flysystem adapter for the PHP content repository", 4 | "keywords": [ 5 | "filesystem", "phpcr", "flysystem" 6 | ], 7 | "authors": [ 8 | { 9 | "name": "David Buchmann", 10 | "email": "david.buchmann@liip.ch" 11 | } 12 | ], 13 | "require": { 14 | "league/flysystem": "~1.0", 15 | "phpcr/phpcr-implementation": "~2.1.0" 16 | }, 17 | "require-dev": { 18 | "phpunit/phpunit": "~4.0", 19 | "jackalope/jackalope-doctrine-dbal": "~1.0" 20 | }, 21 | "autoload": { 22 | "psr-4": { 23 | "League\\Flysystem\\Phpcr\\": "src/" 24 | } 25 | }, 26 | "license": "MIT", 27 | "config": { 28 | "bin-dir": "bin" 29 | }, 30 | "extra": { 31 | "branch-alias": { 32 | "dev-master": "1.1-dev" 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /phpunit.php: -------------------------------------------------------------------------------- 1 | 13 | 14 | 15 | 16 | tests/ 17 | 18 | 19 | 20 | 21 | 22 | src 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /src/PhpcrAdapter.php: -------------------------------------------------------------------------------- 1 | 20 | */ 21 | class PhpcrAdapter extends AbstractAdapter 22 | { 23 | use NotSupportingVisibilityTrait; 24 | 25 | /** 26 | * @var SessionInterface 27 | */ 28 | private $session; 29 | 30 | /** 31 | * Constructor. 32 | * 33 | * @param SessionInterface $session 34 | * @param string $root 35 | */ 36 | public function __construct(SessionInterface $session, $root) 37 | { 38 | $this->session = $session; 39 | if (!$session->nodeExists($root)) { 40 | $parent = NodeHelper::createPath($this->session, PathHelper::getParentPath($root)); 41 | $parent->addNode(PathHelper::getNodeName($root), 'nt:folder'); 42 | } else { 43 | $rootNode = $this->session->getNode($root); 44 | if (!$rootNode->isNodeType('nt:folder')) { 45 | throw new \LogicException(sprintf( 46 | 'The root node at %s must be of type nt:folder, found %s', 47 | $root , 48 | $rootNode->getPrimaryNodeType()->getName()) 49 | ); 50 | } 51 | } 52 | $this->setPathPrefix($root); 53 | } 54 | 55 | /** 56 | * Set the path prefix. 57 | * 58 | * @param string $prefix 59 | * 60 | * @return self 61 | */ 62 | public function setPathPrefix($prefix) 63 | { 64 | parent::setPathPrefix($prefix); 65 | if (null === $this->pathPrefix) { 66 | $this->pathPrefix = $this->pathSeparator; 67 | } 68 | } 69 | 70 | /** 71 | * Prefix a path. 72 | * 73 | * @param string $path 74 | * 75 | * @return string prefixed path 76 | */ 77 | public function applyPathPrefix($path) 78 | { 79 | $path = ltrim($path, '/'); 80 | if (strlen($path) === 0) { 81 | return rtrim($this->getPathPrefix(), '/'); 82 | } 83 | 84 | return $this->getPathPrefix() . $path; 85 | } 86 | 87 | /** 88 | * Ensure the directory exists and try to create it if it does not exist. 89 | * 90 | * @param string $path path relative to the $root. 91 | * @param boolean $create Whether to create the folder if not existing. 92 | * 93 | * @return NodeInterface The node at $root/$path. 94 | */ 95 | private function getFolderNode($path, $create = false) 96 | { 97 | $location = $this->applyPathPrefix($path); 98 | if (!$create && !$this->session->nodeExists($location)) { 99 | // trigger the phpcr exception rather than trying to create parent nodes. 100 | return $this->session->getNode($location); 101 | } 102 | 103 | $folders = array(); 104 | while (!$this->session->nodeExists($location)) { 105 | $folders[] = PathHelper::getNodeName($location); 106 | $location = PathHelper::getParentPath($location); 107 | } 108 | 109 | $node = $this->session->getNode($location); 110 | while (null !== $folder = array_pop($folders)) { 111 | $node = $node->addNode($folder, 'nt:folder'); 112 | } 113 | if (!$node->isNodeType('nt:folder')) { 114 | throw new \LogicException($path.' is not a folder but '.$node->getPrimaryNodeType()->getName()); 115 | } 116 | 117 | if ($create) { 118 | $this->session->save(); 119 | } 120 | 121 | return $node; 122 | } 123 | 124 | /** 125 | * @param string $path path relative to the $root. 126 | * @param bool $create whether to create the file if it does not exist yet. 127 | * 128 | * @return NodeInterface The node at $root/$path 129 | */ 130 | private function getFileNode($path, $create = false) 131 | { 132 | $fileName = PathHelper::getNodeName('/'.$path); 133 | $folderPath = PathHelper::getParentPath('/'.$path); 134 | $folder = $this->getFolderNode($folderPath, $create); 135 | 136 | if ($folder->hasNode($fileName) || !$create) { 137 | return $folder->getNode($fileName); 138 | } 139 | 140 | $file = $folder->addNode($fileName, 'nt:file'); 141 | $file->addNode('jcr:content', 'nt:resource'); 142 | 143 | return $file; 144 | } 145 | 146 | /** 147 | * {@inheritdoc} 148 | */ 149 | public function has($path) 150 | { 151 | $location = $this->applyPathPrefix($path); 152 | 153 | return $this->session->nodeExists($location); 154 | } 155 | 156 | /** 157 | * @param NodeInterface $file 158 | * @param string $path path relative to the $root. 159 | * @param string|resource $contents 160 | * @param Config $config 161 | * 162 | * @return array Metadata for return value. 163 | */ 164 | private function writeMeta(NodeInterface $file, $path, $contents, Config $config) 165 | { 166 | $content = $file->getNode('jcr:content'); 167 | if (!$mimetype = $config->get('mimetype')) { 168 | if (is_string($contents)) { 169 | $mimetype = Util::guessMimeType($path, $contents); 170 | } else { 171 | $mimetype = null; 172 | } 173 | } 174 | $content->setProperty('jcr:mimeType', $mimetype); 175 | 176 | $type = 'file'; 177 | $result = compact('mimetype', 'type', 'path'); 178 | 179 | if ($encoding = $config->get('encoding')) { 180 | $result['encoding'] = $encoding; 181 | $content->setProperty('jcr:encoding', $encoding); 182 | } 183 | if($timestamp = $config->get('timestamp')) { 184 | $result['timestamp'] = $timestamp; 185 | $content->setProperty('jcr:lastModified', $timestamp); 186 | } 187 | 188 | return $result; 189 | } 190 | 191 | /** 192 | * {@inheritdoc} 193 | */ 194 | public function write($path, $contents, Config $config) 195 | { 196 | $file = $this->getFileNode($path, true); 197 | $content = $file->getNode('jcr:content'); 198 | $content->setProperty('jcr:data', $contents, PropertyType::BINARY); 199 | 200 | $result = $this->writeMeta($file, $path, $contents, $config); 201 | $result['size'] = $content->getProperty('jcr:data')->getLength(); 202 | $result['contents'] = $contents; 203 | 204 | $this->session->save(); 205 | 206 | return $result; 207 | } 208 | 209 | /** 210 | * {@inheritdoc} 211 | */ 212 | public function writeStream($path, $resource, Config $config) 213 | { 214 | $file = $this->getFileNode($path, true); 215 | $content = $file->getNode('jcr:content'); 216 | 217 | $content->setProperty('jcr:data', $resource); 218 | 219 | $this->session->save(); 220 | 221 | return $this->writeMeta($file, $path, $resource, $config); 222 | } 223 | 224 | /** 225 | * {@inheritdoc} 226 | */ 227 | public function readStream($path) 228 | { 229 | try { 230 | $file = $this->getFileNode($path); 231 | } catch (PathNotFoundException $e) { 232 | return false; 233 | } 234 | $content = $file->getNode('jcr:content'); 235 | $result = $this->getFileInfo($file); 236 | $result['stream'] = $content->getPropertyValue('jcr:data', PropertyType::BINARY); 237 | 238 | return $result; 239 | } 240 | 241 | /** 242 | * {@inheritdoc} 243 | */ 244 | public function updateStream($path, $resource, Config $config) 245 | { 246 | return $this->writeStream($path, $resource, $config); 247 | } 248 | 249 | /** 250 | * {@inheritdoc} 251 | */ 252 | public function update($path, $contents, Config $config) 253 | { 254 | return $this->write($path, $contents, $config); 255 | } 256 | 257 | /** 258 | * {@inheritdoc} 259 | */ 260 | public function read($path) 261 | { 262 | try { 263 | $file = $this->getFileNode($path); 264 | } catch (PathNotFoundException $e) { 265 | return false; 266 | } 267 | $content = $file->getNode('jcr:content'); 268 | $result = $this->getFileInfo($file); 269 | $result['contents'] = $content->getPropertyValue('jcr:data', PropertyType::STRING); 270 | 271 | return $result; 272 | } 273 | 274 | /** 275 | * {@inheritdoc} 276 | */ 277 | public function rename($path, $newpath) 278 | { 279 | $location = $this->applyPathPrefix($path); 280 | if (!$this->session->nodeExists($location)) { 281 | return false; 282 | } 283 | $destination = $this->applyPathPrefix($newpath); 284 | $parentFolder = $this->applyPathPrefix(PathHelper::getParentPath($newpath)); 285 | $this->getFolderNode($parentFolder, true); 286 | 287 | $this->session->move($location, $destination); 288 | $this->session->save(); 289 | 290 | return true; 291 | } 292 | 293 | /** 294 | * {@inheritdoc} 295 | */ 296 | public function copy($path, $newpath) 297 | { 298 | $location = $this->applyPathPrefix($path); 299 | if (!$this->session->nodeExists($location)) { 300 | return false; 301 | } 302 | $destination = $this->applyPathPrefix($newpath); 303 | $parentFolder = $this->applyPathPrefix(PathHelper::getParentPath($newpath)); 304 | $this->getFolderNode($parentFolder, true); 305 | 306 | $this->session->save(); 307 | $this->session->getWorkspace()->copy($location, $destination); 308 | 309 | return true; 310 | } 311 | 312 | /** 313 | * {@inheritdoc} 314 | */ 315 | public function delete($path) 316 | { 317 | try { 318 | $node = $this->getFileNode($path); 319 | } catch (PathNotFoundException $e) { 320 | return false; 321 | } 322 | $node->remove(); 323 | $this->session->save(); 324 | 325 | return true; 326 | } 327 | 328 | /** 329 | * {@inheritdoc} 330 | */ 331 | public function listContents($directory = '', $recursive = false) 332 | { 333 | try { 334 | $folder = $this->getFolderNode($directory); 335 | } catch (PathNotFoundException $e) { 336 | return array(); 337 | } 338 | 339 | $result = []; 340 | $files = []; 341 | foreach ($folder->getNodes() as $node) { 342 | $files[] = $node; 343 | } 344 | while ($file = array_shift($files)) { 345 | $result[] = $this->getFileInfo($file); 346 | if ($recursive && $file->isNodeType('nt:folder')) { 347 | foreach ($file->getNodes() as $node) { 348 | $files[] = $node; 349 | } 350 | } 351 | } 352 | 353 | return $result; 354 | } 355 | 356 | /** 357 | * {@inheritdoc} 358 | */ 359 | public function getMetadata($path) 360 | { 361 | try { 362 | $file = $this->getFileNode($path); 363 | } catch (PathNotFoundException $e) { 364 | return false; 365 | } 366 | 367 | return $this->getFileInfo($file); 368 | } 369 | 370 | /** 371 | * {@inheritdoc} 372 | */ 373 | public function getSize($path) 374 | { 375 | return $this->getMetadata($path); 376 | } 377 | 378 | /** 379 | * {@inheritdoc} 380 | */ 381 | public function getMimetype($path) 382 | { 383 | return $this->getMetadata($path); 384 | } 385 | 386 | /** 387 | * {@inheritdoc} 388 | */ 389 | public function getTimestamp($path) 390 | { 391 | return $this->getMetadata($path); 392 | } 393 | 394 | private function getFileInfo(NodeInterface $file) 395 | { 396 | $type = $file->isNodeType('nt:folder') ? 'folder' : 'file'; 397 | 398 | $result = array( 399 | 'type' => $type, 400 | 'path' => $this->removePathPrefix($file->getPath()), 401 | ); 402 | 403 | if ('file' === $type) { 404 | $content = $file->getNode('jcr:content'); 405 | $result['size'] = $content->getProperty('jcr:data')->getLength(); 406 | $result['timestamp'] = $content->getPropertyValue('jcr:lastModified', PropertyType::LONG); 407 | if ($content->hasProperty('jcr:mimeType')) { 408 | $result['mimetype'] = $content->getPropertyValue('jcr:mimeType'); 409 | } 410 | if ($content->hasProperty('jcr:encoding')) { 411 | $result['encoding'] = $content->getPropertyValue('jcr:encoding'); 412 | } 413 | } 414 | 415 | return $result; 416 | } 417 | 418 | /** 419 | * {@inheritdoc} 420 | */ 421 | public function createDir($dirname, Config $config) 422 | { 423 | $this->getFolderNode($dirname, true); 424 | 425 | return ['path' => $dirname, 'type' => 'dir']; 426 | } 427 | 428 | /** 429 | * {@inheritdoc} 430 | */ 431 | public function deleteDir($dirname) 432 | { 433 | try { 434 | $this->getFolderNode($dirname)->remove(); 435 | } catch (PathNotFoundException $e) { 436 | return false; 437 | } catch (\LogicException $e) { 438 | return false; 439 | } 440 | $this->session->save(); 441 | 442 | return true; 443 | } 444 | } 445 | -------------------------------------------------------------------------------- /tests/PhpcrAdapterTest.php: -------------------------------------------------------------------------------- 1 | 'pdo_sqlite', 39 | 'path' => sys_get_temp_dir().DIRECTORY_SEPARATOR.'flysystem-test.db', 40 | )); 41 | $options = array('disable_fks' => static::$connection->getDatabasePlatform() instanceof \Doctrine\DBAL\Platforms\SqlitePlatform); 42 | $repositorySchema = new \Jackalope\Transport\DoctrineDBAL\RepositorySchema($options, static::$connection); 43 | $repositorySchema->reset(); 44 | } 45 | 46 | public function setUp() 47 | { 48 | $this->root = '/flysystem_tests'; 49 | 50 | $factory = new RepositoryFactoryDoctrineDBAL(); 51 | $repository = $factory->getRepository(array( 52 | 'jackalope.doctrine_dbal_connection' => static::$connection, 53 | )); 54 | $this->session = $repository->login(new SimpleCredentials('test', 'test')); 55 | if ($this->session->nodeExists($this->root)) { 56 | $this->session->removeItem($this->root); 57 | } 58 | $this->adapter = new PhpcrAdapter($this->session, $this->root); 59 | } 60 | 61 | /** 62 | * @expectedException \LogicException 63 | */ 64 | public function testConstructor() 65 | { 66 | $this->session->getRootNode()->addNode('/flysystem_tests_broken', 'nt:unstructured'); 67 | new PhpcrAdapter($this->session, '/flysystem_tests_broken'); 68 | } 69 | 70 | public function testHasWithDir() 71 | { 72 | $this->adapter->createDir('0', new Config()); 73 | $this->assertTrue($this->adapter->has('0')); 74 | $this->adapter->deleteDir('0'); 75 | } 76 | 77 | public function testHasWithFile() 78 | { 79 | $this->adapter->write('file.txt', 'content', new Config()); 80 | $this->assertTrue($this->adapter->has('file.txt')); 81 | $this->adapter->delete('file.txt'); 82 | } 83 | 84 | public function testReadNotFound() 85 | { 86 | $this->assertFalse($this->adapter->read('file.txt')); 87 | } 88 | 89 | public function testReadFolderNotFound() 90 | { 91 | $this->assertFalse($this->adapter->read('folder/file.txt')); 92 | } 93 | 94 | public function testReadStream() 95 | { 96 | $this->adapter->write('file.txt', 'contents', new Config()); 97 | $result = $this->adapter->readStream('file.txt'); 98 | $this->assertInternalType('array', $result); 99 | $this->assertArrayHasKey('stream', $result); 100 | $this->assertInternalType('resource', $result['stream']); 101 | fclose($result['stream']); 102 | $this->adapter->delete('file.txt'); 103 | } 104 | 105 | public function testReadStreamNotFound() 106 | { 107 | $this->assertFalse($this->adapter->readStream('file.txt')); 108 | } 109 | 110 | public function testUpdate() 111 | { 112 | $this->adapter->update('file.txt', 'content', new Config()); 113 | $this->assertTrue($this->adapter->has('file.txt')); 114 | $this->adapter->delete('file.txt'); 115 | } 116 | 117 | public function testWriteStream() 118 | { 119 | $temp = tmpfile(); 120 | fwrite($temp, 'dummy'); 121 | rewind($temp); 122 | $this->adapter->writeStream('dir/file.txt', $temp, new Config(['visibility' => 'public'])); 123 | //fclose($temp); 124 | $this->assertTrue($this->adapter->has('dir/file.txt')); 125 | $result = $this->adapter->read('dir/file.txt'); 126 | $this->assertEquals('dummy', $result['contents']); 127 | $this->adapter->deleteDir('dir'); 128 | } 129 | 130 | public function testUpdateStream() 131 | { 132 | $this->adapter->write('file.txt', 'initial', new Config()); 133 | $temp = tmpfile(); 134 | fwrite($temp, 'dummy'); 135 | $this->adapter->updateStream('file.txt', $temp, new Config()); 136 | // fclose($temp); 137 | $this->assertTrue($this->adapter->has('file.txt')); 138 | $this->adapter->delete('file.txt'); 139 | } 140 | 141 | public function testCreateZeroDir() 142 | { 143 | $this->adapter->createDir('0', new Config()); 144 | $this->assertTrue($this->session->nodeExists($this->root.'/0')); 145 | $this->adapter->deleteDir('0'); 146 | } 147 | 148 | public function testRename() 149 | { 150 | $this->adapter->write('file.ext', 'content', new Config(['visibility' => 'public'])); 151 | $this->assertTrue($this->adapter->rename('file.ext', 'new.ext')); 152 | $this->assertTrue($this->adapter->has('new.ext')); 153 | $this->assertFalse($this->adapter->has('file.ext')); 154 | $this->adapter->delete('file.ext'); 155 | $this->adapter->delete('new.ext'); 156 | } 157 | 158 | public function testRenameNotExists() 159 | { 160 | $this->assertFalse($this->adapter->rename('file.ext', 'new.ext')); 161 | } 162 | 163 | public function testCopy() 164 | { 165 | $this->adapter->write('file.ext', 'content', new Config(['visibility' => 'public'])); 166 | $this->assertTrue($this->adapter->copy('file.ext', 'new.ext')); 167 | $this->assertTrue($this->adapter->has('new.ext')); 168 | $this->assertTrue($this->adapter->has('file.ext')); 169 | $this->adapter->delete('file.ext'); 170 | $this->adapter->delete('new.ext'); 171 | } 172 | 173 | public function testCopyNotExists() 174 | { 175 | $this->assertFalse($this->adapter->copy('file.ext', 'new.ext')); 176 | } 177 | 178 | public function testListContents() 179 | { 180 | $this->adapter->write('dirname/file.txt', 'contents', new Config()); 181 | $this->adapter->write('dirname/subfolder/file.txt', 'contents', new Config()); 182 | $contents = $this->adapter->listContents('dirname', false); 183 | $this->assertCount(2, $contents); 184 | $this->assertArrayHasKey('type', $contents[0]); 185 | $this->assertEquals('file', $contents[0]['type']); 186 | $this->assertArrayHasKey('type', $contents[1]); 187 | $this->assertEquals('folder', $contents[1]['type']); 188 | } 189 | 190 | public function testListContentsRecursive() 191 | { 192 | $this->adapter->write('dirname/file.txt', 'contents', new Config()); 193 | $this->adapter->write('dirname/subfolder/file.txt', 'contents', new Config()); 194 | $contents = $this->adapter->listContents('dirname', true); 195 | $this->assertCount(3, $contents); 196 | $this->assertArrayHasKey('type', $contents[0]); 197 | $this->assertEquals('file', $contents[0]['type']); 198 | $this->assertArrayHasKey('type', $contents[1]); 199 | $this->assertEquals('folder', $contents[1]['type']); 200 | $this->assertArrayHasKey('type', $contents[2]); 201 | $this->assertEquals('file', $contents[2]['type']); 202 | $this->assertEquals('dirname/subfolder/file.txt', $contents[2]['path']); 203 | } 204 | 205 | public function testListingNonexistingDirectory() 206 | { 207 | $result = $this->adapter->listContents('nonexisting/directory'); 208 | $this->assertEquals([], $result); 209 | } 210 | 211 | public function testGetMetadataFolder() 212 | { 213 | $this->adapter->createDir('test', new Config()); 214 | $result = $this->adapter->getMetadata('test'); 215 | $this->assertInternalType('array', $result); 216 | $this->assertArrayHasKey('type', $result); 217 | $this->assertEquals('folder', $result['type']); 218 | } 219 | 220 | public function testGetMetadataNotExisting() 221 | { 222 | $this->assertFalse($this->adapter->getMetadata('dummy.txt')); 223 | } 224 | 225 | public function testGetSize() 226 | { 227 | $this->adapter->write('dummy.txt', '1234', new Config()); 228 | $result = $this->adapter->getSize('dummy.txt'); 229 | $this->assertInternalType('array', $result); 230 | $this->assertArrayHasKey('size', $result); 231 | $this->assertEquals(4, $result['size']); 232 | } 233 | 234 | public function testGetTimestamp() 235 | { 236 | $this->adapter->write('dummy.txt', '1234', new Config()); 237 | $result = $this->adapter->getTimestamp('dummy.txt'); 238 | $this->assertInternalType('array', $result); 239 | $this->assertArrayHasKey('timestamp', $result); 240 | $this->assertInternalType('int', $result['timestamp']); 241 | } 242 | 243 | public function testGetMimetype() 244 | { 245 | $this->adapter->write('text.txt', 'contents', new Config()); 246 | $result = $this->adapter->getMimetype('text.txt'); 247 | $this->assertInternalType('array', $result); 248 | $this->assertArrayHasKey('mimetype', $result); 249 | $this->assertEquals('text/plain', $result['mimetype']); 250 | } 251 | 252 | public function testGetEncoding() 253 | { 254 | $this->adapter->write('text.txt', 'contents', new Config(array('encoding' => 'utf-8'))); 255 | $result = $this->adapter->getMimetype('text.txt'); 256 | $this->assertInternalType('array', $result); 257 | $this->assertArrayHasKey('encoding', $result); 258 | $this->assertEquals('utf-8', $result['encoding']); 259 | } 260 | 261 | public function testDeleteDir() 262 | { 263 | $this->adapter->write('nested/dir/path.txt', 'contents', new Config()); 264 | $this->assertTrue($this->session->nodeExists($this->root.'/nested/dir/path.txt')); 265 | $this->assertTrue($this->adapter->deleteDir('nested')); 266 | $this->assertFalse($this->adapter->has('nested/dir/path.txt')); 267 | $this->assertFalse($this->session->nodeExists($this->root.'/nested')); 268 | } 269 | 270 | public function testDeleteDirNotFound() 271 | { 272 | $this->assertFalse($this->adapter->deleteDir('nested')); 273 | } 274 | 275 | public function testDeleteDirIsFile() 276 | { 277 | $this->adapter->write('dir/path.txt', 'contents', new Config()); 278 | $this->assertTrue($this->session->nodeExists($this->root.'/dir/path.txt')); 279 | $this->assertFalse($this->adapter->deleteDir('dir/path.txt')); 280 | } 281 | 282 | /** 283 | * @expectedException \LogicException 284 | */ 285 | public function testVisibilityPublic() 286 | { 287 | $this->adapter->write('path.txt', 'contents', new Config()); 288 | $this->adapter->setVisibility('path.txt', 'public'); 289 | } 290 | 291 | /** 292 | * @expectedException \LogicException 293 | */ 294 | public function testVisibilityPrivate() 295 | { 296 | $this->adapter->write('path.txt', 'contents', new Config()); 297 | $this->adapter->setVisibility('path.txt', 'private'); 298 | } 299 | 300 | public function testApplyPathPrefix() 301 | { 302 | $this->adapter->setPathPrefix(''); 303 | $this->assertEquals('', $this->adapter->applyPathPrefix('')); 304 | } 305 | 306 | public function testApplyPathPrefixAbsolute() 307 | { 308 | $this->adapter->setPathPrefix($this->root . '/'); 309 | $this->assertEquals($this->root, $this->adapter->applyPathPrefix('/')); 310 | } 311 | 312 | public function testWriteWithSpecificTimestampInConfig() 313 | { 314 | $timestamp = strtotime('today midnight'); 315 | $this->adapter->write('dummy.txt', '1234', new Config(['timestamp' => $timestamp])); 316 | $result = $this->adapter->getTimestamp('dummy.txt'); 317 | $this->assertInternalType('array', $result); 318 | $this->assertArrayHasKey('timestamp', $result); 319 | $this->assertInternalType('int', $result['timestamp']); 320 | $this->assertEquals($timestamp, $result['timestamp']); 321 | } 322 | } 323 | --------------------------------------------------------------------------------