1<?php
2/**
3 * Zend Framework (http://framework.zend.com/)
4 *
5 * @link      http://github.com/zendframework/zf2 for the canonical source repository
6 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
7 * @license   http://framework.zend.com/license/new-bsd New BSD License
8 */
9
10namespace Zend\Filter;
11
12use Traversable;
13use Zend\Stdlib\ArrayUtils;
14
15/**
16 * Compresses a given string
17 */
18class Compress extends AbstractFilter
19{
20    /**
21     * Compression adapter
22     */
23    protected $adapter = 'Gz';
24
25    /**
26     * Compression adapter constructor options
27     */
28    protected $adapterOptions = array();
29
30    /**
31     * Class constructor
32     *
33     * @param string|array|Traversable $options (Optional) Options to set
34     */
35    public function __construct($options = null)
36    {
37        if ($options instanceof Traversable) {
38            $options = ArrayUtils::iteratorToArray($options);
39        }
40        if (is_string($options)) {
41            $this->setAdapter($options);
42        } elseif ($options instanceof Compress\CompressionAlgorithmInterface) {
43            $this->setAdapter($options);
44        } elseif (is_array($options)) {
45            $this->setOptions($options);
46        }
47    }
48
49    /**
50     * Set filter setate
51     *
52     * @param  array $options
53     * @throws Exception\InvalidArgumentException if options is not an array or Traversable
54     * @return self
55     */
56    public function setOptions($options)
57    {
58        if (!is_array($options) && !$options instanceof Traversable) {
59            throw new Exception\InvalidArgumentException(sprintf(
60                '"%s" expects an array or Traversable; received "%s"',
61                __METHOD__,
62                (is_object($options) ? get_class($options) : gettype($options))
63            ));
64        }
65
66        foreach ($options as $key => $value) {
67            if ($key == 'options') {
68                $key = 'adapterOptions';
69            }
70            $method = 'set' . ucfirst($key);
71            if (method_exists($this, $method)) {
72                $this->$method($value);
73            }
74        }
75        return $this;
76    }
77
78    /**
79     * Returns the current adapter, instantiating it if necessary
80     *
81     * @throws Exception\RuntimeException
82     * @throws Exception\InvalidArgumentException
83     * @return Compress\CompressionAlgorithmInterface
84     */
85    public function getAdapter()
86    {
87        if ($this->adapter instanceof Compress\CompressionAlgorithmInterface) {
88            return $this->adapter;
89        }
90
91        $adapter = $this->adapter;
92        $options = $this->getAdapterOptions();
93        if (!class_exists($adapter)) {
94            $adapter = 'Zend\\Filter\\Compress\\' . ucfirst($adapter);
95            if (!class_exists($adapter)) {
96                throw new Exception\RuntimeException(sprintf(
97                    '%s unable to load adapter; class "%s" not found',
98                    __METHOD__,
99                    $this->adapter
100                ));
101            }
102        }
103
104        $this->adapter = new $adapter($options);
105        if (!$this->adapter instanceof Compress\CompressionAlgorithmInterface) {
106            throw new Exception\InvalidArgumentException("Compression adapter '" . $adapter . "' does not implement Zend\\Filter\\Compress\\CompressionAlgorithmInterface");
107        }
108        return $this->adapter;
109    }
110
111    /**
112     * Retrieve adapter name
113     *
114     * @return string
115     */
116    public function getAdapterName()
117    {
118        return $this->getAdapter()->toString();
119    }
120
121    /**
122     * Sets compression adapter
123     *
124     * @param  string|Compress\CompressionAlgorithmInterface $adapter Adapter to use
125     * @return self
126     * @throws Exception\InvalidArgumentException
127     */
128    public function setAdapter($adapter)
129    {
130        if ($adapter instanceof Compress\CompressionAlgorithmInterface) {
131            $this->adapter = $adapter;
132            return $this;
133        }
134        if (!is_string($adapter)) {
135            throw new Exception\InvalidArgumentException('Invalid adapter provided; must be string or instance of Zend\\Filter\\Compress\\CompressionAlgorithmInterface');
136        }
137        $this->adapter = $adapter;
138
139        return $this;
140    }
141
142    /**
143     * Retrieve adapter options
144     *
145     * @return array
146     */
147    public function getAdapterOptions()
148    {
149        return $this->adapterOptions;
150    }
151
152    /**
153     * Set adapter options
154     *
155     * @param  array $options
156     * @return self
157     */
158    public function setAdapterOptions(array $options)
159    {
160        $this->adapterOptions = $options;
161        return $this;
162    }
163
164    /**
165     * Get individual or all options from underlying adapter
166     *
167     * @param  null|string $option
168     * @return mixed
169     */
170    public function getOptions($option = null)
171    {
172        $adapter = $this->getAdapter();
173        return $adapter->getOptions($option);
174    }
175
176    /**
177     * Calls adapter methods
178     *
179     * @param string       $method  Method to call
180     * @param string|array $options Options for this method
181     * @return mixed
182     * @throws Exception\BadMethodCallException
183     */
184    public function __call($method, $options)
185    {
186        $adapter = $this->getAdapter();
187        if (!method_exists($adapter, $method)) {
188            throw new Exception\BadMethodCallException("Unknown method '{$method}'");
189        }
190
191        return call_user_func_array(array($adapter, $method), $options);
192    }
193
194    /**
195     * Defined by Zend\Filter\FilterInterface
196     *
197     * Compresses the content $value with the defined settings
198     *
199     * @param  string $value Content to compress
200     * @return string The compressed content
201     */
202    public function filter($value)
203    {
204        if (!is_string($value)) {
205            return $value;
206        }
207
208        return $this->getAdapter()->compress($value);
209    }
210}
211