Issues (26)

src/Compressy.php (1 issue)

Labels
Severity
1
<?php
2
/*
3
 * This file is part of Compressy.
4
 *
5
 * (c) Alchemy <[email protected]>
6
 * (c) Miguel Gocobachi <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
namespace Gocobachi\Compressy;
12
13
use Gocobachi\Compressy\Adapter\AdapterContainer;
14
use Gocobachi\Compressy\Adapter\AdapterInterface;
15
use Gocobachi\Compressy\Archive\ArchiveInterface;
16
use Gocobachi\Compressy\Exception\ExceptionInterface;
17
use Gocobachi\Compressy\Exception\FormatNotSupportedException;
18
use Gocobachi\Compressy\Exception\NoAdapterOnPlatformException;
19
use Gocobachi\Compressy\Exception\RuntimeException;
20
use Gocobachi\Compressy\FileStrategy\FileStrategyInterface;
21
use Gocobachi\Compressy\FileStrategy\TarBz2FileStrategy;
22
use Gocobachi\Compressy\FileStrategy\TarFileStrategy;
23
use Gocobachi\Compressy\FileStrategy\TarGzFileStrategy;
24
use Gocobachi\Compressy\FileStrategy\TB2FileStrategy;
25
use Gocobachi\Compressy\FileStrategy\TBz2FileStrategy;
26
use Gocobachi\Compressy\FileStrategy\TGzFileStrategy;
27
use Gocobachi\Compressy\FileStrategy\ZipFileStrategy;
28
29
class Compressy
30
{
31
    /**
32
     * @var AdapterContainer
33
     */
34
    public $adapters;
35
36
    /**
37
     * @var FileStrategyInterface[][]
38
     */
39
    private $strategies = array();
40
41
    public function __construct(AdapterContainer $adapters)
42
    {
43
        $this->adapters = $adapters;
44
    }
45
46
    /**
47
     * Creates an archive
48
     *
49
     * @param string                         $path
50
     * @param string|array|\Traversable|null $files
51
     * @param bool                           $recursive
52
     * @param string|null                    $type
53
     *
54
     * @return ArchiveInterface
55
     *
56
     * @throws RuntimeException In case of failure
57
     */
58
    public function create($path, $files = null, $recursive = true, $type = null)
59
    {
60
        if (null === $type) {
61
            $type = $this->guessAdapterExtension($path);
62
        }
63
64
        try {
65
            return $this
66
                    ->getAdapterFor($this->sanitizeExtension($type))
67
                    ->create($path, $files, $recursive);
68
        } catch (ExceptionInterface $e) {
69
            throw new RuntimeException('Unable to create archive', $e->getCode(), $e);
0 ignored issues
show
The method getCode() does not exist on Gocobachi\Compressy\Exception\ExceptionInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to Gocobachi\Compressy\Exception\ExceptionInterface. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

69
            throw new RuntimeException('Unable to create archive', $e->/** @scrutinizer ignore-call */ getCode(), $e);
Loading history...
70
        }
71
    }
72
73
    /**
74
     * Opens an archive.
75
     *
76
     * @param string $path
77
     *
78
     * @return ArchiveInterface
79
     *
80
     * @throws RuntimeException In case of failure
81
     */
82
    public function open($path, $type = null)
83
    {
84
        if (null === $type) {
85
            $type = $this->guessAdapterExtension($path);
86
        }
87
88
        try {
89
            return $this
90
                    ->getAdapterFor($this->sanitizeExtension($type))
91
                    ->open($path);
92
        } catch (ExceptionInterface $e) {
93
            throw new RuntimeException('Unable to open archive', $e->getCode(), $e);
94
        }
95
    }
96
97
    /**
98
     * Adds a strategy.
99
     *
100
     * The last strategy added is preferred over the other ones.
101
     * You can add a strategy twice ; when doing this, the first one is removed
102
     * when inserting the second one.
103
     *
104
     * @param FileStrategyInterface $strategy
105
     *
106
     * @return Compressy
107
     */
108
    public function addStrategy(FileStrategyInterface $strategy)
109
    {
110
        $extension = $this->sanitizeExtension($strategy->getFileExtension());
111
112
        if (!isset($this->strategies[$extension])) {
113
            $this->strategies[$extension] = array();
114
        }
115
116
        if (false !== $key = array_search($strategy, $this->strategies[$extension], true)) {
117
            unset($this->strategies[$extension][$key]);
118
        }
119
120
        array_unshift($this->strategies[$extension], $strategy);
121
122
        return $this;
123
    }
124
125
    /**
126
     * Returns the strategies as they are stored
127
     *
128
     * @return array
129
     */
130
    public function getStrategies()
131
    {
132
        return $this->strategies;
133
    }
134
135
    /**
136
     * Returns an adapter for a file extension
137
     *
138
     * @param string $extension The extension
139
     *
140
     * @return AdapterInterface
141
     *
142
     * @throws FormatNotSupportedException  When no strategy is defined for this extension
143
     * @throws NoAdapterOnPlatformException When no adapter is supported for this extension on this platform
144
     */
145
    public function getAdapterFor($extension)
146
    {
147
        $extension = $this->sanitizeExtension($extension);
148
149
        if (!$extension || !isset($this->strategies[$extension])) {
150
            throw new FormatNotSupportedException(sprintf('No strategy for %s extension', $extension));
151
        }
152
153
        foreach ($this->strategies[$extension] as $strategy) {
154
            foreach ($strategy->getAdapters() as $adapter) {
155
                if ($adapter->isSupported()) {
156
                    return $adapter;
157
                }
158
            }
159
        }
160
161
        throw new NoAdapterOnPlatformException(sprintf('No adapter available for %s on this platform', $extension));
162
    }
163
164
    /**
165
     * Creates Compressy and loads default strategies
166
     *
167
     * @return Compressy
168
     */
169
    public static function load()
170
    {
171
        $adapters = AdapterContainer::load();
172
        $factory = new static($adapters);
173
174
        $factory->addStrategy(new ZipFileStrategy($adapters));
175
        $factory->addStrategy(new TarFileStrategy($adapters));
176
        $factory->addStrategy(new TarGzFileStrategy($adapters));
177
        $factory->addStrategy(new TarBz2FileStrategy($adapters));
178
        $factory->addStrategy(new TB2FileStrategy($adapters));
179
        $factory->addStrategy(new TBz2FileStrategy($adapters));
180
        $factory->addStrategy(new TGzFileStrategy($adapters));
181
182
        return $factory;
183
    }
184
185
    /**
186
     * Sanitize an extension.
187
     *
188
     * Strips dot from the beginning, converts to lowercase and remove trailing
189
     * whitespaces
190
     *
191
     * @param string $extension
192
     *
193
     * @return string
194
     */
195
    private function sanitizeExtension($extension)
196
    {
197
        return ltrim(trim(mb_strtolower($extension)), '.');
198
    }
199
200
    /**
201
     * Finds an extension that has strategy registered given a file path
202
     *
203
     * Returns null if no matching strategy found.
204
     *
205
     * @param string $path
206
     *
207
     * @return string|null
208
     */
209
    private function guessAdapterExtension($path)
210
    {
211
        $path = strtolower(trim($path));
212
213
        foreach ($this->strategies as $extension => $strategy) {
214
            if ($extension === substr($path, (strlen($extension) * -1))) {
215
                return $extension;
216
            }
217
        }
218
219
        return null;
220
    }
221
}
222