Completed
Push — 4-cactus ( 35f1a2...d71008 )
by Stefano
16s queued 11s
created

BEdita/Core/src/Filesystem/FilesystemRegistry.php (1 issue)

1
<?php
2
/**
3
 * BEdita, API-first content management framework
4
 * Copyright 2017 ChannelWeb Srl, Chialab Srl
5
 *
6
 * This file is part of BEdita: you can redistribute it and/or modify
7
 * it under the terms of the GNU Lesser General Public License as published
8
 * by the Free Software Foundation, either version 3 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * See LICENSE.LGPL or <http://gnu.org/licenses/lgpl-3.0.html> for more details.
12
 */
13
14
namespace BEdita\Core\Filesystem;
15
16
use BEdita\Core\Filesystem\Adapter\LocalAdapter;
17
use BEdita\Core\SingletonTrait;
18
use Cake\Core\App;
19
use Cake\Core\ObjectRegistry;
20
use Cake\Core\StaticConfigTrait;
21
use League\Flysystem\Filesystem;
22
use League\Flysystem\FilesystemNotFoundException;
23
use League\Flysystem\MountManager;
24
25
/**
26
 * Registry for filesystem adapters.
27
 *
28
 * @since 4.0.0
29
 */
30
class FilesystemRegistry extends ObjectRegistry
31
{
32
33
    use SingletonTrait;
34
    use StaticConfigTrait;
35
36
    /**
37
     * Mount manager.
38
     *
39
     * @var \League\Flysystem\MountManager
40
     */
41
    protected $mountManager;
42
43
    /**
44
     * An array mapping url schemes to fully qualified Log engine class names
45
     *
46
     * @var array
47
     */
48
    protected static $_dsnClassMap = [
49
        'local' => LocalAdapter::class,
50
    ];
51
52
    /**
53
     * {@inheritDoc}
54
     */
55
    protected function _resolveClassName($class)
56
    {
57
        if (is_object($class)) {
58
            return $class;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $class returns the type object which is incompatible with the return type mandated by Cake\Core\ObjectRegistry::_resolveClassName() of boolean|string.

In the issue above, the returned value is violating the contract defined by the mentioned interface.

Let's take a look at an example:

interface HasName {
    /** @return string */
    public function getName();
}

class Name {
    public $name;
}

class User implements HasName {
    /** @return string|Name */
    public function getName() {
        return new Name('foo'); // This is a violation of the ``HasName`` interface
                                // which only allows a string value to be returned.
    }
}
Loading history...
59
        }
60
61
        return App::className($class, 'Filesystem/Adapter', 'Adapter');
62
    }
63
64
    /**
65
     * {@inheritDoc}
66
     */
67
    protected function _throwMissingClassError($class, $plugin)
68
    {
69
        throw new \BadMethodCallException(sprintf('Filesystem adapter %s is not available.', $class));
70
    }
71
72
    /**
73
     * {@inheritDoc}
74
     */
75
    protected function _create($class, $alias, $config)
76
    {
77
        if (is_object($class)) {
78
            $instance = $class;
79
        }
80
81
        unset($config['className']);
82
        if (!isset($instance)) {
83
            $instance = new $class($config);
84
        }
85
86
        if (!($instance instanceof FilesystemAdapter)) {
87
            throw new \RuntimeException(
88
                sprintf('Filesystem adapters must use %s as a base class.', FilesystemAdapter::class)
89
            );
90
        }
91
92
        if (!$instance->initialize($config)) {
93
            throw new \RuntimeException(
94
                sprintf('Filesystem adapter %s is not properly configured.', get_class($instance))
95
            );
96
        }
97
98
        return $instance;
99
    }
100
101
    /**
102
     * {@inheritDoc}
103
     *
104
     * @return \BEdita\Core\Filesystem\FilesystemAdapter|null
105
     */
106
    public function get($name)
107
    {
108
        /* @var \BEdita\Core\Filesystem\FilesystemAdapter|null $adapter */
109
        $adapter = parent::get($name);
110
        if ($adapter !== null || !in_array($name, static::configured())) {
111
            return $adapter;
112
        }
113
114
        return $this->load($name, static::getConfig($name));
115
    }
116
117
    /**
118
     * Drop all filesystems.
119
     *
120
     * @return void
121
     */
122
    public static function dropAll()
123
    {
124
        foreach (static::configured() as $config) {
125
            static::drop($config);
126
        }
127
128
        $instance = static::getInstance();
129
        $instance->reset();
130
        $instance->mountManager = null;
131
    }
132
133
    /**
134
     * Get mount manager to transparently handle files basing on the prefix.
135
     *
136
     * @return \League\Flysystem\MountManager
137
     */
138
    public static function getMountManager()
139
    {
140
        $instance = static::getInstance();
141
        if (!empty($instance->mountManager)) {
142
            return $instance->mountManager;
143
        }
144
145
        $filesystems = [];
146
        foreach (static::configured() as $prefix) {
147
            $adapter = $instance->get($prefix);
148
            $filesystems[$prefix] = new Filesystem($adapter->getInnerAdapter(), [
149
                'visibility' => $adapter->getVisibility(),
150
            ]);
151
        }
152
153
        return $instance->mountManager = new MountManager($filesystems);
154
    }
155
156
    /**
157
     * Get public URL for a file.
158
     *
159
     * @param string $path Original path.
160
     * @return string
161
     * @throws \League\Flysystem\FilesystemNotFoundException Throws an exception if a filesystem with such prefix
162
     *      could not be found.
163
     */
164
    public static function getPublicUrl($path)
165
    {
166
        list($prefix, $path) = static::getPrefixAndPath($path);
167
168
        $adapter = static::getInstance()->get($prefix);
169
        if ($adapter === null) {
170
            throw new FilesystemNotFoundException(sprintf('No filesystem mounted with prefix %s', $prefix));
171
        }
172
173
        return $adapter->getPublicUrl($path);
174
    }
175
176
    /**
177
     * Split path into prefix and path.
178
     *
179
     * @see \League\Flysystem\MountManager::getPrefixAndPath()
180
     * @param string $path Original path.
181
     * @return string[]
182
     * @throws \InvalidArgumentException Throws an exception if path could not be parsed.
183
     */
184
    protected static function getPrefixAndPath($path)
185
    {
186
        if (!is_string($path) || strpos($path, '://') < 1) {
187
            throw new \InvalidArgumentException(sprintf('No prefix detected in path: %s', $path));
188
        }
189
190
        return explode('://', $path, 2);
191
    }
192
}
193