4 * This file is part of Zippy.
6 * (c) Alchemy <info@alchemy.fr>
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
12 namespace Alchemy\Zippy;
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;
33 * @var AdapterContainer
38 * @var FileStrategyInterface[][]
40 private $strategies = array();
42 public function __construct(AdapterContainer $adapters)
44 $this->adapters = $adapters;
51 * @param string|array|\Traversable|null $files
52 * @param bool $recursive
53 * @param string|null $type
55 * @return ArchiveInterface
57 * @throws RuntimeException In case of failure
59 public function create($path, $files = null, $recursive = true, $type = null)
62 $type = $this->guessAdapterExtension($path);
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);
79 * @return ArchiveInterface
81 * @throws RuntimeException In case of failure
83 public function open($path)
85 $type = $this->guessAdapterExtension($path);
89 ->getAdapterFor($this->sanitizeExtension($type))
91 } catch (ExceptionInterface $e) {
92 throw new RuntimeException('Unable to open archive', $e->getCode(), $e);
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.
103 * @param FileStrategyInterface $strategy
107 public function addStrategy(FileStrategyInterface $strategy)
109 $extension = $this->sanitizeExtension($strategy->getFileExtension());
111 if (!isset($this->strategies[$extension])) {
112 $this->strategies[$extension] = array();
115 if (false !== $key = array_search($strategy, $this->strategies[$extension], true)) {
116 unset($this->strategies[$extension][$key]);
119 array_unshift($this->strategies[$extension], $strategy);
125 * Returns the strategies as they are stored
129 public function getStrategies()
131 return $this->strategies;
135 * Returns an adapter for a file extension
137 * @param string $extension The extension
139 * @return AdapterInterface
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
144 public function getAdapterFor($extension)
146 $extension = $this->sanitizeExtension($extension);
148 if (!$extension || !isset($this->strategies[$extension])) {
149 throw new FormatNotSupportedException(sprintf('No strategy for %s extension', $extension));
152 foreach ($this->strategies[$extension] as $strategy) {
153 foreach ($strategy->getAdapters() as $adapter) {
154 if ($adapter->isSupported()) {
160 throw new NoAdapterOnPlatformException(sprintf('No adapter available for %s on this platform', $extension));
164 * Creates Zippy and loads default strategies
168 public static function load()
170 $adapters = AdapterContainer::load();
171 $factory = new static($adapters);
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));
185 * Sanitize an extension.
187 * Strips dot from the beginning, converts to lowercase and remove trailing
190 * @param string $extension
194 private function sanitizeExtension($extension)
196 return ltrim(trim(mb_strtolower($extension)), '.');
200 * Finds an extension that has strategy registered given a file path
202 * Returns null if no matching strategy found.
204 * @param string $path
206 * @return string|null
208 private function guessAdapterExtension($path)
210 $path = strtolower(trim($path));
212 foreach ($this->strategies as $extension => $strategy) {
213 if ($extension === substr($path, (strlen($extension) * -1))) {