Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
92.86% covered (success)
92.86%
13 / 14
50.00% covered (danger)
50.00%
1 / 2
CRAP
0.00% covered (danger)
0.00%
0 / 1
FlysystemAdapterBackCompatTrait
92.86% covered (success)
92.86%
13 / 14
50.00% covered (danger)
50.00%
1 / 2
8.02
0.00% covered (danger)
0.00%
0 / 1
 directoryExists
66.67% covered (warning)
66.67%
2 / 3
0.00% covered (danger)
0.00%
0 / 1
3.33
 directoryExistsImplementation
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
5
1<?php
2/**
3 * `FilesystemAdapter` interface v3 introduced `::directoryExists()`.
4 *
5 * When this trait is used with your implementation of {@see \League\Flysystem\FilesystemAdapter} and
6 * `league/flysystem` v3 is installed, the genuine parent method is used; when v2 is installed the trait
7 * provides an implementation.
8 *
9 * v2: https://github.com/thephpleague/flysystem/blob/2.x/src/FilesystemAdapter.php
10 * Interface: https://github.com/thephpleague/flysystem/blob/3.x/src/FilesystemAdapter.php
11 * Implementations:
12 * https://github.com/thephpleague/flysystem/blob/3.x/src/Filesystem.php#L41-L44
13 * https://github.com/thephpleague/flysystem/blob/3.x/src/Local/LocalFilesystemAdapter.php#L346-L351
14 *
15 * @package BrianHenryIE\FlysystemReadOnly
16 */
17
18namespace BrianHenryIE\FlysystemReadOnly;
19
20use League\Flysystem\FileAttributes;
21use League\Flysystem\FilesystemAdapter;
22use League\Flysystem\FilesystemException;
23
24/**
25 * Back-fills `FilesystemAdapter::directoryExists()` when `league/flysystem` v2 is installed.
26 *
27 * @mixin FlysystemAdapterBackCompatTraitInterface
28 *
29 * @method string normalizePath($location)
30 * @method iterable<\League\Flysystem\StorageAttributes> listContents(string $path, bool $deep)
31 */
32trait FlysystemAdapterBackCompatTrait
33{
34    /**
35     * Determine whether a directory exists, using the parent's implementation where there is one.
36     *
37     * @param string $path The path to check.
38     *
39     * @throws FilesystemException
40     *
41     * @see FilesystemAdapter::directoryExists()
42     */
43    public function directoryExists(string $path): bool
44    {
45        /**
46         * Use `self::class` here to check the parent of the current class, not necessarily the parent of the class
47         * which was called.
48         *
49         * @phpstan-ignore booleanAnd.leftAlwaysTrue
50         */
51        if (get_parent_class(self::class) && method_exists(get_parent_class(self::class), 'directoryExists')) {
52            /**
53             * The parent's `::directoryExists()` is not declared by v2's `FilesystemAdapter`, so its
54             * return value is untyped there; anything other than `true` is treated as not existing.
55             *
56             * @phpstan-ignore staticMethod.notFound
57             */
58            return true === parent::directoryExists($path);
59        }
60
61        return $this->directoryExistsImplementation($path);
62    }
63
64    /**
65     * Determine whether a directory exists by listing its parent directory and looking for it.
66     *
67     * @param string $path The path to check.
68     *
69     * @throws FilesystemException
70     */
71    protected function directoryExistsImplementation(string $path): bool
72    {
73        $path = $this->normalizePath($path);
74
75        $parentDir = dirname($path);
76        $parentDir = $this->normalizePath($parentDir);
77        // TODO: This might not be Windows compatible.
78        $parentDir = $parentDir === '.' ? '/' : $parentDir;
79
80        // Root dir must exist!
81        if ($parentDir === $path) {
82            return true;
83        }
84
85        $parentDirectoryContents = $this->listContents($parentDir, false);
86        /**
87         * Listings yield `StorageAttributes`; both its implementations expose `::isDir()`.
88         *
89         * @var FileAttributes $entry
90         */
91        foreach ($parentDirectoryContents as $entry) {
92            if ($entry->path() == $path) {
93                return $entry->isDir();
94            }
95        }
96
97        return false;
98    }
99}