--- /dev/null
+<?php
+
+/*
+ * This file is part of Zippy.
+ *
+ * (c) Alchemy <info@alchemy.fr>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ */
+
+namespace Alchemy\Zippy\Adapter;
+
+use Alchemy\Zippy\Adapter\Resource\ResourceInterface;
+use Alchemy\Zippy\Adapter\VersionProbe\VersionProbeInterface;
+use Alchemy\Zippy\Archive\Archive;
+use Alchemy\Zippy\Archive\ArchiveInterface;
+use Alchemy\Zippy\Exception\RuntimeException;
+use Alchemy\Zippy\Exception\InvalidArgumentException;
+use Alchemy\Zippy\Resource\PathUtil;
+use Alchemy\Zippy\Resource\ResourceManager;
+
+abstract class AbstractAdapter implements AdapterInterface
+{
+ /** @var ResourceManager */
+ protected $manager;
+
+ /**
+ * The version probe
+ *
+ * @var VersionProbeInterface
+ */
+ protected $probe;
+
+ public function __construct(ResourceManager $manager)
+ {
+ $this->manager = $manager;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function open($path)
+ {
+ $this->requireSupport();
+
+ return new Archive($this->createResource($path), $this, $this->manager);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function create($path, $files = null, $recursive = true)
+ {
+ $this->requireSupport();
+
+ return $this->doCreate($this->makeTargetAbsolute($path), $files, $recursive);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function listMembers(ResourceInterface $resource)
+ {
+ $this->requireSupport();
+
+ return $this->doListMembers($resource);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function add(ResourceInterface $resource, $files, $recursive = true)
+ {
+ $this->requireSupport();
+
+ return $this->doAdd($resource, $files, $recursive);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function remove(ResourceInterface $resource, $files)
+ {
+ $this->requireSupport();
+
+ return $this->doRemove($resource, $files);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function extract(ResourceInterface $resource, $to = null)
+ {
+ $this->requireSupport();
+
+ return $this->doExtract($resource, $to);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function extractMembers(ResourceInterface $resource, $members, $to = null, $overwrite = false)
+ {
+ $this->requireSupport();
+
+ return $this->doExtractMembers($resource, $members, $to, $overwrite);
+ }
+
+ /**
+ * Returns the version probe used by this adapter
+ *
+ * @return VersionProbeInterface
+ */
+ public function getVersionProbe()
+ {
+ return $this->probe;
+ }
+
+ /**
+ * Sets the version probe used by this adapter
+ *
+ * @param VersionProbeInterface $probe
+ *
+ * @return VersionProbeInterface
+ */
+ public function setVersionProbe(VersionProbeInterface $probe)
+ {
+ $this->probe = $probe;
+
+ return $this;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function isSupported()
+ {
+ if (!$this->probe) {
+ throw new RuntimeException(sprintf(
+ 'No version probe has been set on %s whereas it is required', get_class($this)
+ ));
+ }
+
+ return VersionProbeInterface::PROBE_OK === $this->probe->getStatus();
+ }
+
+ /**
+ * Throws an exception is the current adapter is not supported
+ *
+ * @throws RuntimeException
+ */
+ protected function requireSupport()
+ {
+ if (false === $this->isSupported()) {
+ throw new RuntimeException(sprintf('%s is not supported on your system', get_class($this)));
+ }
+ }
+
+ /**
+ * Change current working directory to another
+ *
+ * @param string $target the target directory
+ *
+ * @return AdapterInterface
+ *
+ * @throws RuntimeException In case of failure
+ */
+ protected function chdir($target)
+ {
+ if (false === @chdir($target)) {
+ throw new RuntimeException(sprintf('Unable to chdir to `%s`', $target));
+ }
+
+ return $this;
+ }
+
+ /**
+ * Creates a resource given a path
+ *
+ * @param string $path
+ *
+ * @return ResourceInterface
+ */
+ abstract protected function createResource($path);
+
+ /**
+ * Do the removal after having check that the current adapter is supported
+ *
+ * @param ResourceInterface $resource
+ * @param array $files
+ *
+ * @return array
+ */
+ abstract protected function doRemove(ResourceInterface $resource, $files);
+
+ /**
+ * Do the add after having check that the current adapter is supported
+ *
+ * @param ResourceInterface $resource
+ * @param array $files
+ * @param bool $recursive
+ *
+ * @return array
+ */
+ abstract protected function doAdd(ResourceInterface $resource, $files, $recursive);
+
+ /**
+ * Do the extract after having check that the current adapter is supported
+ *
+ * @param ResourceInterface $resource
+ * @param $to
+ *
+ * @return \SplFileInfo The extracted archive
+ */
+ abstract protected function doExtract(ResourceInterface $resource, $to);
+
+ /**
+ * Do the extract members after having check that the current adapter is supported
+ *
+ * @param ResourceInterface $resource
+ * @param string|string[] $members
+ * @param string $to
+ * @param bool $overwrite
+ *
+ * @return \SplFileInfo The extracted archive
+ */
+ abstract protected function doExtractMembers(ResourceInterface $resource, $members, $to, $overwrite = false);
+
+ /**
+ * Do the list members after having check that the current adapter is supported
+ *
+ * @param ResourceInterface $resource
+ *
+ * @return array
+ */
+ abstract protected function doListMembers(ResourceInterface $resource);
+
+ /**
+ * Do the create after having check that the current adapter is supported
+ *
+ * @param string $path
+ * @param string $file
+ * @param bool $recursive
+ *
+ * @return ArchiveInterface
+ */
+ abstract protected function doCreate($path, $file, $recursive);
+
+ /**
+ * Makes the target path absolute as the adapters might have a different directory
+ *
+ * @param string $path The path to convert
+ *
+ * @return string The absolute path
+ *
+ * @throws InvalidArgumentException In case the path is not writable or does not exist
+ */
+ private function makeTargetAbsolute($path)
+ {
+ $directory = dirname($path);
+
+ if (!is_dir($directory)) {
+ throw new InvalidArgumentException(sprintf('Target path %s does not exist.', $directory));
+ }
+ if (!is_writable($directory)) {
+ throw new InvalidArgumentException(sprintf('Target path %s is not writeable.', $directory));
+ }
+
+ return realpath($directory) . '/' . PathUtil::basename($path);
+ }
+}