Version 1
[yaffs-website] / vendor / alchemy / zippy / src / Zippy.php
1 <?php
2
3 /*
4  * This file is part of Zippy.
5  *
6  * (c) Alchemy <info@alchemy.fr>
7  *
8  * For the full copyright and license information, please view the LICENSE
9  * file that was distributed with this source code.
10  */
11
12 namespace Alchemy\Zippy;
13
14 use Alchemy\Zippy\Adapter\AdapterContainer;
15 use Alchemy\Zippy\Adapter\AdapterInterface;
16 use Alchemy\Zippy\Archive\ArchiveInterface;
17 use Alchemy\Zippy\Exception\ExceptionInterface;
18 use Alchemy\Zippy\Exception\FormatNotSupportedException;
19 use Alchemy\Zippy\Exception\NoAdapterOnPlatformException;
20 use Alchemy\Zippy\Exception\RuntimeException;
21 use Alchemy\Zippy\FileStrategy\FileStrategyInterface;
22 use Alchemy\Zippy\FileStrategy\TarBz2FileStrategy;
23 use Alchemy\Zippy\FileStrategy\TarFileStrategy;
24 use Alchemy\Zippy\FileStrategy\TarGzFileStrategy;
25 use Alchemy\Zippy\FileStrategy\TB2FileStrategy;
26 use Alchemy\Zippy\FileStrategy\TBz2FileStrategy;
27 use Alchemy\Zippy\FileStrategy\TGzFileStrategy;
28 use Alchemy\Zippy\FileStrategy\ZipFileStrategy;
29
30 class Zippy
31 {
32     /**
33      * @var AdapterContainer
34      */
35     public $adapters;
36
37     /**
38      * @var FileStrategyInterface[][]
39      */
40     private $strategies = array();
41
42     public function __construct(AdapterContainer $adapters)
43     {
44         $this->adapters = $adapters;
45     }
46
47     /**
48      * Creates an archive
49      *
50      * @param string                         $path
51      * @param string|array|\Traversable|null $files
52      * @param bool                           $recursive
53      * @param string|null                    $type
54      *
55      * @return ArchiveInterface
56      *
57      * @throws RuntimeException In case of failure
58      */
59     public function create($path, $files = null, $recursive = true, $type = null)
60     {
61         if (null === $type) {
62             $type = $this->guessAdapterExtension($path);
63         }
64
65         try {
66             return $this
67                     ->getAdapterFor($this->sanitizeExtension($type))
68                     ->create($path, $files, $recursive);
69         } catch (ExceptionInterface $e) {
70             throw new RuntimeException('Unable to create archive', $e->getCode(), $e);
71         }
72     }
73
74     /**
75      * Opens an archive.
76      *
77      * @param string $path
78      *
79      * @return ArchiveInterface
80      *
81      * @throws RuntimeException In case of failure
82      */
83     public function open($path)
84     {
85         $type = $this->guessAdapterExtension($path);
86
87         try {
88             return $this
89                     ->getAdapterFor($this->sanitizeExtension($type))
90                     ->open($path);
91         } catch (ExceptionInterface $e) {
92             throw new RuntimeException('Unable to open archive', $e->getCode(), $e);
93         }
94     }
95
96     /**
97      * Adds a strategy.
98      *
99      * The last strategy added is preferred over the other ones.
100      * You can add a strategy twice ; when doing this, the first one is removed
101      * when inserting the second one.
102      *
103      * @param FileStrategyInterface $strategy
104      *
105      * @return Zippy
106      */
107     public function addStrategy(FileStrategyInterface $strategy)
108     {
109         $extension = $this->sanitizeExtension($strategy->getFileExtension());
110
111         if (!isset($this->strategies[$extension])) {
112             $this->strategies[$extension] = array();
113         }
114
115         if (false !== $key = array_search($strategy, $this->strategies[$extension], true)) {
116             unset($this->strategies[$extension][$key]);
117         }
118
119         array_unshift($this->strategies[$extension], $strategy);
120
121         return $this;
122     }
123
124     /**
125      * Returns the strategies as they are stored
126      *
127      * @return array
128      */
129     public function getStrategies()
130     {
131         return $this->strategies;
132     }
133
134     /**
135      * Returns an adapter for a file extension
136      *
137      * @param string $extension The extension
138      *
139      * @return AdapterInterface
140      *
141      * @throws FormatNotSupportedException  When no strategy is defined for this extension
142      * @throws NoAdapterOnPlatformException When no adapter is supported for this extension on this platform
143      */
144     public function getAdapterFor($extension)
145     {
146         $extension = $this->sanitizeExtension($extension);
147
148         if (!$extension || !isset($this->strategies[$extension])) {
149             throw new FormatNotSupportedException(sprintf('No strategy for %s extension', $extension));
150         }
151
152         foreach ($this->strategies[$extension] as $strategy) {
153             foreach ($strategy->getAdapters() as $adapter) {
154                 if ($adapter->isSupported()) {
155                     return $adapter;
156                 }
157             }
158         }
159
160         throw new NoAdapterOnPlatformException(sprintf('No adapter available for %s on this platform', $extension));
161     }
162
163     /**
164      * Creates Zippy and loads default strategies
165      *
166      * @return Zippy
167      */
168     public static function load()
169     {
170         $adapters = AdapterContainer::load();
171         $factory = new static($adapters);
172
173         $factory->addStrategy(new ZipFileStrategy($adapters));
174         $factory->addStrategy(new TarFileStrategy($adapters));
175         $factory->addStrategy(new TarGzFileStrategy($adapters));
176         $factory->addStrategy(new TarBz2FileStrategy($adapters));
177         $factory->addStrategy(new TB2FileStrategy($adapters));
178         $factory->addStrategy(new TBz2FileStrategy($adapters));
179         $factory->addStrategy(new TGzFileStrategy($adapters));
180
181         return $factory;
182     }
183
184     /**
185      * Sanitize an extension.
186      *
187      * Strips dot from the beginning, converts to lowercase and remove trailing
188      * whitespaces
189      *
190      * @param string $extension
191      *
192      * @return string
193      */
194     private function sanitizeExtension($extension)
195     {
196         return ltrim(trim(mb_strtolower($extension)), '.');
197     }
198
199     /**
200      * Finds an extension that has strategy registered given a file path
201      *
202      * Returns null if no matching strategy found.
203      *
204      * @param string $path
205      *
206      * @return string|null
207      */
208     private function guessAdapterExtension($path)
209     {
210         $path = strtolower(trim($path));
211
212         foreach ($this->strategies as $extension => $strategy) {
213             if ($extension === substr($path, (strlen($extension) * -1))) {
214                 return $extension;
215             }
216         }
217
218         return null;
219     }
220 }