<?php
namespace PhpZip\Extra;
use PhpZip\Exception\InvalidArgumentException;
use PhpZip\Exception\ZipException;
/**
* Represents a collection of Extra Fields as they may
* be present at several locations in ZIP files.
*
* @author Ne-Lexa [email protected]
* @license MIT
*/
class ExtraFieldsCollection implements \Countable, \ArrayAccess, \Iterator
{
/**
* The map of Extra Fields.
* Maps from Header ID to Extra Field.
* Must not be null, but may be empty if no Extra Fields are used.
* The map is sorted by Header IDs in ascending order.
*
* @var ExtraField[]
*/
protected $collection = [];
/**
* Returns the number of Extra Fields in this collection.
*
* @return int
*/
public function count()
{
return \count($this->collection);
}
/**
* Returns the Extra Field with the given Header ID or null
* if no such Extra Field exists.
*
* @param int $headerId the requested Header ID
*
* @throws ZipException if headerId is out of range
*
* @return ExtraField|null the Extra Field with the given Header ID or
* if no such Extra Field exists
*/
public function get($headerId)
{
if ($headerId < 0x0000 || $headerId > 0xffff) {
throw new ZipException('headerId out of range');
}
if (isset($this->collection[$headerId])) {
return $this->collection[$headerId];
}
return null;
}
/**
* Stores the given Extra Field in this collection.
*
* @param ExtraField $extraField the Extra Field to store in this collection
*
* @throws ZipException if headerId is out of range
*
* @return ExtraField the Extra Field previously associated with the Header ID of
* of the given Extra Field or null if no such Extra Field existed
*/
public function add(ExtraField $extraField)
{
$headerId = $extraField::getHeaderId();
if ($headerId < 0x0000 || $headerId > 0xffff) {
throw new ZipException('headerId out of range');
}
$this->collection[$headerId] = $extraField;
return $extraField;
}
/**
* Returns Extra Field exists.
*
* @param int $headerId the requested Header ID
*
* @return bool
*/
public function has($headerId)
{
return isset($this->collection[$headerId]);
}
/**
* Removes the Extra Field with the given Header ID.
*
* @param int $headerId the requested Header ID
*
* @throws ZipException if headerId is out of range or extra field not found
*
* @return ExtraField the Extra Field with the given Header ID or null
* if no such Extra Field exists
*/
public function remove($headerId)
{
if ($headerId < 0x0000 || $headerId > 0xffff) {
throw new ZipException('headerId out of range');
}
if (isset($this->collection[$headerId])) {
$ef = $this->collection[$headerId];
unset($this->collection[$headerId]);
return $ef;
}
throw new ZipException('ExtraField not found');
}
/**
* Whether a offset exists.
*
* @see http://php.net/manual/en/arrayaccess.offsetexists.php
*
* @param mixed $offset <p>
* An offset to check for.
* </p>
*
* @return bool true on success or false on failure.
* </p>
* <p>
* The return value will be casted to boolean if non-boolean was returned.
*
* @since 5.0.0
*/
public function offsetExists($offset)
{
return isset($this->collection[$offset]);
}
/**
* Offset to retrieve.
*
* @see http://php.net/manual/en/arrayaccess.offsetget.php
*
* @param mixed $offset <p>
* The offset to retrieve.
* </p>
*
* @throws ZipException
*
* @return mixed can return all value types
*
* @since 5.0.0
*/
public function offsetGet($offset)
{
return $this->get($offset);
}
/**
* Offset to set.
*
* @see http://php.net/manual/en/arrayaccess.offsetset.php
*
* @param mixed $offset <p>
* The offset to assign the value to.
* </p>
* @param mixed $value <p>
* The value to set.
* </p>
*
* @throws ZipException
*
* @since 5.0.0
*/
public function offsetSet($offset, $value)
{
if ($value instanceof ExtraField) {
if ($offset !== $value::getHeaderId()) {
throw new InvalidArgumentException('Value header id !== array access key');
}
$this->add($value);
} else {
throw new InvalidArgumentException('value is not instanceof ' . ExtraField::class);
}
}
/**
* Offset to unset.
*
* @see http://php.net/manual/en/arrayaccess.offsetunset.php
*
* @param mixed $offset <p>
* The offset to unset.
* </p>
*
* @since 5.0.0
*
* @throws ZipException
*/
public function offsetUnset($offset)
{
$this->remove($offset);
}
/**
* Return the current element.
*
* @see http://php.net/manual/en/iterator.current.php
*
* @return mixed can return any type
*
* @since 5.0.0
*/
public function current()
{
return current($this->collection);
}
/**
* Move forward to next element.
*
* @see http://php.net/manual/en/iterator.next.php
* @since 5.0.0
*/
public function next()
{
next($this->collection);
}
/**
* Return the key of the current element.
*
* @see http://php.net/manual/en/iterator.key.php
*
* @return mixed scalar on success, or null on failure
*
* @since 5.0.0
*/
public function key()
{
return key($this->collection);
}
/**
* Checks if current position is valid.
*
* @see http://php.net/manual/en/iterator.valid.php
*
* @return bool The return value will be casted to boolean and then evaluated.
* Returns true on success or false on failure.
*
* @since 5.0.0
*/
public function valid()
{
return $this->offsetExists($this->key());
}
/**
* Rewind the Iterator to the first element.
*
* @see http://php.net/manual/en/iterator.rewind.php
* @since 5.0.0
*/
public function rewind()
{
reset($this->collection);
}
/**
* If clone extra fields.
*/
public function __clone()
{
foreach ($this->collection as $k => $v) {
$this->collection[$k] = clone $v;
}
}
}