Completed
Push — master ( e24932...fec1b8 )
by Chris
01:58
created

Stat::getWithMetadata()   B

Complexity

Conditions 4
Paths 4

Size

Total Lines 26
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 4

Importance

Changes 0
Metric Value
dl 0
loc 26
c 0
b 0
f 0
ccs 12
cts 12
cp 1
rs 8.5806
cc 4
eloc 12
nc 4
nop 2
crap 4
1
<?php
2
3
namespace Twistor\Flysystem\Plugin;
4
5
use League\Flysystem\AdapterInterface;
6
use Twistor\FlysystemStreamWrapper;
7
use Twistor\PosixUid;
8
use Twistor\Uid;
9
10
class Stat extends AbstractPlugin
11
{
12
    /**
13
     * Default return value of url_stat().
14
     *
15
     * @var array
16
     */
17
    protected static $defaultMeta = [
18
        'dev' => 0,
19
        'ino' => 0,
20
        'mode' => 0,
21
        'nlink' => 0,
22
        'uid' => 0,
23
        'gid' => 0,
24
        'rdev' => 0,
25
        'size' => 0,
26
        'atime' => 0,
27
        'mtime' => 0,
28
        'ctime' => 0,
29
        'blksize' => -1,
30
        'blocks' => -1,
31
    ];
32
33
    /**
34
     * Permission map.
35
     *
36
     * @var array
37
     */
38
    protected $permissions;
39
40
    /**
41
     * Required metadata.
42
     *
43
     * @var array
44
     */
45
    protected $required;
46
47
    /**
48
     * @var \Twistor\Uid
49
     */
50
    protected $uid;
51
52
    /**
53
     * Constructs a Stat object.
54
     *
55
     * @param array $permissions An array of permissions.
56
     * @param array $metadata    The default required metadata.
57
     */
58 213
    public function __construct(array $permissions, array $metadata)
59
    {
60 213
        $this->permissions = $permissions;
61 213
        $this->required = array_combine($metadata, $metadata);
62 213
        $this->uid = \extension_loaded('posix') ? new PosixUid() : Uid();
63 213
    }
64
65
    /**
66
     * {@inheritdoc}
67
     */
68 210
    public function getMethod()
69
    {
70 210
        return 'stat';
71
    }
72
73
    /**
74
     * Emulates stat().
75
     *
76
     * @param string $path
77
     * @param int    $flags
78
     *
79
     * @return array Output similar to stat().
80
     *
81
     * @see stat()
82
     */
83 87
    public function handle($path, $flags)
84
    {
85 87
        if ($path === '') {
86 6
            return $this->mergeMeta(['type' => 'dir', 'visibility' => AdapterInterface::VISIBILITY_PUBLIC]);
87
        }
88
89 81
        $ignore = $flags & FlysystemStreamWrapper::STREAM_URL_IGNORE_SIZE ? ['size'] : [];
90
91 81
        $metadata = $this->getWithMetadata($path, $ignore);
92
93
        // It's possible for getMetadata() to fail even if a file exists.
94 69
        if (empty($metadata)) {
95 3
            return static::$defaultMeta;
96
        }
97
98 69
        return $this->mergeMeta($metadata + ['visibility' => AdapterInterface::VISIBILITY_PUBLIC]);
99
    }
100
101
    /**
102
     * Returns metadata.
103
     *
104
     * @param string $path   The path to get metadata for.
105
     * @param array  $ignore Metadata to ignore.
106
     *
107
     * @return array The metadata as returned by Filesystem::getMetadata().
108
     *
109
     * @see \League\Flysystem\Filesystem::getMetadata()
110
     */
111 81
    protected function getWithMetadata($path, array $ignore)
112
    {
113 81
        $metadata = $this->filesystem->getMetadata($path);
114
115 69
        if (empty($metadata)) {
116 3
            return [];
117
        }
118
119 69
        $keys = array_diff($this->required, array_keys($metadata), $ignore);
120
121 69
        foreach ($keys as $key) {
122 69
            $method = 'get' . ucfirst($key);
123
124
            try {
125 69
                $metadata[$key] = $this->filesystem->$method($path);
126 69
            } catch (\LogicException $e) {
127
                // Some adapters don't support certain metadata. For instance,
128
                // the Dropbox adapter throws exceptions when calling
129
                // getVisibility(). Remove the required key so we don't keep
130
                // calling it.
131 3
                unset($this->required[$key]);
132
            }
133 69
        }
134
135 69
        return $metadata;
136
    }
137
138
    /**
139
     * Merges the available metadata from Filesystem::getMetadata().
140
     *
141
     * @param array $metadata The metadata.
142
     *
143
     * @return array All metadata with default values filled in.
144
     */
145 75
    protected function mergeMeta(array $metadata)
146
    {
147 75
        $ret = static::$defaultMeta;
148
149 75
        $ret['uid'] = $this->uid->getUid();
150 75
        $ret['gid'] = $this->uid->getGid();
151
152 75
        $ret['mode'] = $metadata['type'] === 'dir' ? 040000 : 0100000;
153 75
        $ret['mode'] += $this->permissions[$metadata['type']][$metadata['visibility']];
154
155 75
        if (isset($metadata['size'])) {
156 69
            $ret['size'] = (int) $metadata['size'];
157 69
        }
158 75
        if (isset($metadata['timestamp'])) {
159 69
            $ret['mtime'] = (int) $metadata['timestamp'];
160 69
            $ret['ctime'] = (int) $metadata['timestamp'];
161 69
        }
162
163 75
        $ret['atime'] = time();
164
165 75
        return array_merge(array_values($ret), $ret);
166
    }
167
}
168