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 */
31trait FlysystemAdapterBackCompatTrait
32{
33    /**
34     * Determine whether a directory exists, using the parent's implementation where there is one.
35     *
36     * @param string $path The path to check.
37     *
38     * @throws FilesystemException
39     *
40     * @see FilesystemAdapter::directoryExists()
41     */
42    public function directoryExists(string $path): bool
43    {
44        /**
45         * Use `self::class` here to check the parent of the current class, not necessarily the parent of the class
46         * which was called.
47         *
48         * @phpstan-ignore booleanAnd.leftAlwaysTrue
49         */
50        if (get_parent_class(self::class) && method_exists(get_parent_class(self::class), 'directoryExists')) {
51            /**
52             * The parent's `::directoryExists()` is not declared by v2's `FilesystemAdapter`, so its
53             * return value is untyped there; anything other than `true` is treated as not existing.
54             *
55             * @phpstan-ignore staticMethod.notFound
56             */
57            return true === parent::directoryExists($path);
58        }
59
60        return $this->directoryExistsImplementation($path);
61    }
62
63    /**
64     * Determine whether a directory exists by listing its parent directory and looking for it.
65     *
66     * @param string $path The path to check.
67     *
68     * @throws FilesystemException
69     */
70    protected function directoryExistsImplementation(string $path): bool
71    {
72        $path = $this->normalizePath($path);
73
74        $parentDir = dirname($path);
75        $parentDir = $this->normalizePath($parentDir);
76        // TODO: This might not be Windows compatible.
77        $parentDir = $parentDir === '.' ? '/' : $parentDir;
78
79        // Root dir must exist!
80        if ($parentDir === $path) {
81            return true;
82        }
83
84        $parentDirectoryContents = $this->listContents($parentDir, false);
85        /**
86         * Listings yield `StorageAttributes`; both its implementations expose `::isDir()`.
87         *
88         * @var FileAttributes $entry
89         */
90        foreach ($parentDirectoryContents as $entry) {
91            if ($entry->path() == $path) {
92                return $entry->isDir();
93            }
94        }
95
96        return false;
97    }
98}