Refactor Archive to be OO and add Documentation #89

Merged
merged 5 commits into from Mar 26, 2013
@@ -8,8 +8,6 @@
namespace Joomla\Archive;
-use Joomla\Factory;
-use Joomla\Filesystem\Path;
use Joomla\Filesystem\File;
use Joomla\Filesystem\Folder;
@@ -26,7 +24,31 @@ class Archive
* @var array
* @since 1.0
*/
- protected static $adapters = array();
+ protected $adapters = array();
+
+ /**
+ * Holds the options array.
+ *
+ * @var mixed Array or object that implements \ArrayAccess
+ * @since 1.0
+ */
+ public $options = array();
+
+ /**
+ * Create a new Archive object.
+ *
+ * @param mixed $options An array of options or an object that implements \ArrayAccess
+ *
+ * @since 1.0
+ */
+ public function __construct($options = array())
+ {
+ // Make sure we have a tmp directory.
+ isset($options['tmp_path']) or $options['tmp_path'] = realpath(sys_get_temp_dir());
+
+ $this->options = $options;
+ }
+
/**
* Extract an archive file to a directory.
@@ -39,126 +61,81 @@ class Archive
* @since 1.0
* @throws \InvalidArgumentException
*/
- public static function extract($archivename, $extractdir)
+ public function extract($archivename, $extractdir)
{
- $untar = false;
$result = false;
- $ext = File::getExt(strtolower($archivename));
-
- // Check if a tar is embedded...gzip/bzip2 can just be plain files!
- if (File::getExt(File::stripExt(strtolower($archivename))) == 'tar')
- {
- $untar = true;
- }
+ $ext = pathinfo($archivename, PATHINFO_EXTENSION);
+ $path = pathinfo($archivename, PATHINFO_DIRNAME);
+ $filename = pathinfo($archivename, PATHINFO_FILENAME);
switch ($ext)
{
case 'zip':
- $adapter = self::getAdapter('zip');
-
- if ($adapter)
- {
- $result = $adapter->extract($archivename, $extractdir);
- }
+ $result = $this->getAdapter('zip')->extract($archivename, $extractdir);
break;
case 'tar':
- $adapter = self::getAdapter('tar');
-
- if ($adapter)
- {
- $result = $adapter->extract($archivename, $extractdir);
- }
+ $result = $this->getAdapter('tar')->extract($archivename, $extractdir);
break;
case 'tgz':
- // This format is a tarball gzip'd
- $untar = true;
-
case 'gz':
case 'gzip':
// This may just be an individual file (e.g. sql script)
- $adapter = self::getAdapter('gzip');
+ $tmpfname = $this->options['tmp_path'] . '/' . uniqid('gzip');
+ $gzresult = $this->getAdapter('gzip')->extract($archivename, $tmpfname);
- if ($adapter)
+ if ($gzresult instanceof \Exception)
{
- $config = Factory::getConfig();
- $tmpfname = $config->get('tmp_path') . '/' . uniqid('gzip');
- $gzresult = $adapter->extract($archivename, $tmpfname);
-
- if ($gzresult instanceof \Exception)
- {
- @unlink($tmpfname);
-
- return false;
- }
-
- if ($untar)
- {
- // Try to untar the file
- $tadapter = self::getAdapter('tar');
-
- if ($tadapter)
- {
- $result = $tadapter->extract($tmpfname, $extractdir);
- }
- }
- else
- {
- $path = Path::clean($extractdir);
- Folder::create($path);
- $result = File::copy($tmpfname, $path . '/' . File::stripExt(basename(strtolower($archivename))), null, 1);
- }
-
@unlink($tmpfname);
+
+ return false;
+ }
+
+ if ($ext === 'tgz' || stripos($filename, '.tar') !== false)
+ {
+ $result = $this->getAdapter('tar')->extract($tmpfname, $extractdir);
+ }
+ else
+ {
+ Folder::create($path);
+ $result = File::copy($tmpfname, $extractdir, null, 0);
}
+
+ @unlink($tmpfname);
+
break;
case 'tbz2':
- // This format is a tarball bzip2'd
- $untar = true;
-
case 'bz2':
case 'bzip2':
// This may just be an individual file (e.g. sql script)
- $adapter = self::getAdapter('bzip2');
+ $tmpfname = $this->options['tmp_path'] . '/' . uniqid('bzip2');
+ $bzresult = $this->getAdapter('bzip2')->extract($archivename, $tmpfname);
- if ($adapter)
+ if ($bzresult instanceof \Exception)
{
- $config = Factory::getConfig();
- $tmpfname = $config->get('tmp_path') . '/' . uniqid('bzip2');
- $bzresult = $adapter->extract($archivename, $tmpfname);
-
- if ($bzresult instanceof \Exception)
- {
- @unlink($tmpfname);
-
- return false;
- }
-
- if ($untar)
- {
- // Try to untar the file
- $tadapter = self::getAdapter('tar');
-
- if ($tadapter)
- {
- $result = $tadapter->extract($tmpfname, $extractdir);
- }
- }
- else
- {
- $path = Path::clean($extractdir);
- Folder::create($path);
- $result = File::copy($tmpfname, $path . '/' . File::stripExt(basename(strtolower($archivename))), null, 1);
- }
-
@unlink($tmpfname);
+
+ return false;
}
+
+ if ($ext === 'tbz2' || stripos($filename, '.tar') !== false)
+ {
+ $result = $this->getAdapter('tar')->extract($tmpfname, $extractdir);
+ }
+ else
+ {
+ Folder::create($path);
+ $result = File::copy($tmpfname, $extractdir, null, 0);
+ }
+
+ @unlink($tmpfname);
+
break;
default:
- throw new \InvalidArgumentException('Unknown Archive Type');
+ throw new \InvalidArgumentException(sprintf('Unknown archive type: %s', $ext));
}
if (!$result || $result instanceof \Exception)
@@ -170,6 +147,33 @@ public static function extract($archivename, $extractdir)
}
/**
+ * Method to override the provided adapter with your own implementation.
+ *
+ * @param string $type Name of the adapter to set.
+ * @param string $class FQCN of your class which implements ExtractableInterface.
+ * @param object $override True to force override the adapter type.
+ *
+ * @return Archive This object for chaining.
+ *
+ * @since 1.0
+ * @throws \InvalidArgumentException
+ */
+ public function setAdapter($type, $class, $override = true)
+ {
+ if (!($class instanceof ExtractableInterface))
+ {
+ throw new \InvalidArgumentException(sprintf('The provided %s adapter %s must implement Joomla\\Archive\\ExtractableInterface', $type), 500);
+ }
+
+ if ($override || !isset($this->adapters[$type]))
+ {
+ $this->adapters[$type] = new $class($this->options);
+ }
+
+ return $this;
+ }
+
+ /**
* Get a file compression adapter.
*
* @param string $type The type of adapter (bzip2|gzip|tar|zip).
@@ -179,21 +183,23 @@ public static function extract($archivename, $extractdir)
* @since 1.0
* @throws \UnexpectedValueException
*/
- public static function getAdapter($type)
+ public function getAdapter($type)
{
- if (!isset(self::$adapters[$type]))
+ $type = strtolower($type);
+
+ if (!isset($this->adapters[$type]))
{
// Try to load the adapter object
$class = 'Joomla\\Archive\\' . ucfirst($type);
- if (!class_exists($class))
+ if (!class_exists($class) || !$class::isSupported())
{
- throw new \UnexpectedValueException(sprintf('Unable to load archive adapter %s.', $type) , 500);
+ throw new \UnexpectedValueException(sprintf('Archive adapter %s not found or supported.', $type), 500);
}
- self::$adapters[$type] = new $class;
+ $this->adapters[$type] = new $class($this->options);
}
- return self::$adapters[$type];
+ return $this->adapters[$type];
}
}
@@ -27,27 +27,41 @@ class Bzip2 implements ExtractableInterface
private $data = null;
/**
+ * Holds the options array.
+ *
+ * @var mixed Array or object that implements \ArrayAccess
+ * @since 1.0
+ */
+ protected $options = array();
+
+ /**
+ * Create a new Archive object.
+ *
+ * @param mixed $options An array of options or an object that implements \ArrayAccess
+ *
+ * @since 1.0
+ */
+ public function __construct($options = array())
+ {
+ $this->options = $options;
+ }
+
+ /**
* Extract a Bzip2 compressed file to a given path
*
* @param string $archive Path to Bzip2 archive to extract
* @param string $destination Path to extract archive to
- * @param array $options Extraction options [unused]
*
* @return boolean True if successful
*
* @since 1.0
* @throws \RuntimeException
*/
- public function extract($archive, $destination, array $options = array ())
+ public function extract($archive, $destination)
{
$this->data = null;
- if (!extension_loaded('bz2'))
- {
- throw new \RuntimeException('The bz2 extension is not available.');
- }
-
- if (!isset($options['use_streams']) || $options['use_streams'] == false)
+ if (!isset($this->options['use_streams']) || $this->options['use_streams'] == false)
{
// Old style: read the whole file and then parse it
$this->data = file_get_contents($archive);
@@ -26,7 +26,7 @@
*
* @since 1.0
*/
- public function extract($archive, $destination, array $options = array());
+ public function extract($archive, $destination);
/**
* Tests whether this adapter can unpack files on this computer.
@@ -41,27 +41,41 @@ class Gzip implements ExtractableInterface
private $data = null;
/**
+ * Holds the options array.
+ *
+ * @var mixed Array or object that implements \ArrayAccess
+ * @since 1.0
+ */
+ protected $options = array();
+
+ /**
+ * Create a new Archive object.
+ *
+ * @param mixed $options An array of options or an object that implements \ArrayAccess
+ *
+ * @since 1.0
+ */
+ public function __construct($options = array())
+ {
+ $this->options = $options;
+ }
+
+ /**
* Extract a Gzip compressed file to a given path
*
* @param string $archive Path to ZIP archive to extract
* @param string $destination Path to extract archive to
- * @param array $options Extraction options [unused]
*
* @return boolean True if successful
*
* @since 1.0
* @throws \RuntimeException
*/
- public function extract($archive, $destination, array $options = array ())
+ public function extract($archive, $destination)
{
$this->data = null;
- if (!extension_loaded('zlib'))
- {
- throw new \RuntimeException('The zlib extension is not available.');
- }
-
- if (!isset($options['use_streams']) || $options['use_streams'] == false)
+ if (!isset($this->options['use_streams']) || $this->options['use_streams'] == false)
{
$this->data = file_get_contents($archive);
@@ -124,6 +138,7 @@ public function extract($archive, $destination, array $options = array ())
$output->close();
$input->close();
}
+
return true;
}
Oops, something went wrong.