1<?php
2
3/**
4 * Hoa
5 *
6 *
7 * @license
8 *
9 * New BSD License
10 *
11 * Copyright © 2007-2017, Hoa community. All rights reserved.
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions are met:
15 *     * Redistributions of source code must retain the above copyright
16 *       notice, this list of conditions and the following disclaimer.
17 *     * Redistributions in binary form must reproduce the above copyright
18 *       notice, this list of conditions and the following disclaimer in the
19 *       documentation and/or other materials provided with the distribution.
20 *     * Neither the name of the Hoa nor the names of its contributors may be
21 *       used to endorse or promote products derived from this software without
22 *       specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
25 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE
28 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 * POSSIBILITY OF SUCH DAMAGE.
35 */
36
37namespace Hoa\Stream\Filter;
38
39use Hoa\Consistency;
40use Hoa\Stream;
41
42/**
43 * Class \Hoa\Stream\Filter.
44 *
45 * Proposes some methods to handle filter.
46 *
47 * @copyright  Copyright © 2007-2017 Hoa community
48 * @license    New BSD License
49 */
50abstract class Filter extends Stream
51{
52    /**
53     * Overwrite filter if already exists.
54     *
55     * @const bool
56     */
57    const OVERWRITE        = true;
58
59    /**
60     * Do not overwrite filter if already exists.
61     *
62     * @const bool
63     */
64    const DO_NOT_OVERWRITE = false;
65
66    /**
67     * Filter should only be applied when reading.
68     *
69     * @const int
70     */
71    const READ             = STREAM_FILTER_READ;
72
73    /**
74     * Filter should only be applied when writing.
75     *
76     * @const int
77     */
78    const WRITE            = STREAM_FILTER_WRITE;
79
80    /**
81     * Filter should be applied when reading and writing.
82     *
83     * @const int
84     */
85    const READ_AND_WRITE   = STREAM_FILTER_ALL;
86
87    /**
88     * All resources with at least one filter registered.
89     *
90     * @var array
91     */
92    protected static $_resources = [];
93
94
95
96    /**
97     * Register a stream filter.
98     *
99     * @param   string  $name         Filter name.
100     * @param   mixed   $class        Class name or instance.
101     * @param   bool    $overwrite    Overwrite filter if already exists or
102     *                                not. Given by self::*OVERWRITE constants.
103     * @return  bool
104     * @throws  \Hoa\Stream\Filter\Exception
105     */
106    public static function register(
107        $name,
108        $class,
109        $overwrite = self::DO_NOT_OVERWRITE
110    ) {
111        if ($overwrite === self::DO_NOT_OVERWRITE &&
112            true       === self::isRegistered($name)) {
113            throw new Exception('Filter %s is already registered.', 0, $name);
114        }
115
116        if (is_object($class)) {
117            $class = get_class($class);
118        }
119
120        if (empty($name)) {
121            throw new Exception(
122                'Filter name cannot be empty (implementation class is %s).',
123                1,
124                $class
125            );
126        }
127
128        if (false === class_exists($class, false)) {
129            throw new Exception(
130                'Cannot register the %s class for the filter %s ' .
131                'because it does not exist.',
132                2,
133                [$class, $name]
134            );
135        }
136
137        return stream_filter_register($name, $class);
138    }
139
140    /**
141     * Append a filter to the list of filters.
142     *
143     * @param   mixed       $stream        Stream which received the filter.
144     *                                     Should be resource or an object
145     *                                     of kind `Hoa\Stream`.
146     * @param   string      $name          Filter name.
147     * @param   int         $mode          `self::READ`, `self::WRITE` or
148     *                                     `self::READ_AND_WRITE`.
149     * @param   mixed       $parameters    Parameters.
150     * @return  resource
151     */
152    public static function append(
153        $stream,
154        $name,
155        $mode       = self::READ,
156        $parameters = null
157    ) {
158        if ($stream instanceof Stream) {
159            $stream = $stream->getStream();
160        }
161
162        if (null === $parameters) {
163            return self::$_resources[$name] = stream_filter_append(
164                $stream,
165                $name,
166                $mode
167            );
168        }
169
170        return self::$_resources[$name] = stream_filter_append(
171            $stream,
172            $name,
173            $mode,
174            $parameters
175        );
176    }
177
178    /**
179     * Prepend a filter to the list of filters.
180     *
181     * @param   mixed       $stream        Stream which received the filter.
182     *                                     Should be resource or an object
183     *                                     \Hoa\Stream.
184     * @param   string      $name          Filter name.
185     * @param   int         $mode          self::READ, self::WRITE or
186     *                                     self::READ_AND_WRITE.
187     * @param   mixed       $parameters    Parameters.
188     * @return  resource
189     */
190    public static function prepend(
191        $stream,
192        $name,
193        $mode = self::READ, $parameters = null
194    ) {
195        if ($stream instanceof Stream) {
196            $stream = $stream->getStream();
197        }
198
199        if (null === $parameters) {
200            return self::$_resources[$name] = stream_filter_prepend(
201                $stream,
202                $name,
203                $mode
204            );
205        }
206
207        return self::$_resources[$name] = stream_filter_prepend(
208            $stream,
209            $name,
210            $mode,
211            $parameters
212        );
213    }
214
215    /**
216     * Delete a filter.
217     *
218     * @param   mixed   $streamFilter    Stream filter resource or name.
219     * @return  bool
220     * @throws  \Hoa\Stream\Filter\Exception
221     */
222    public static function remove($streamFilter)
223    {
224        if (!is_resource($streamFilter)) {
225            if (isset(self::$_resources[$streamFilter])) {
226                $streamFilter = self::$_resources[$streamFilter];
227            } else {
228                throw new Exception(
229                    'Cannot remove the stream filter %s because no resource was ' .
230                    'found with this name.',
231                    3,
232                    $streamFilter
233                );
234            }
235        }
236
237        return stream_filter_remove($streamFilter);
238    }
239
240    /**
241     * Check if a filter is already registered or not.
242     *
243     * @param   string  $name    Filter name.
244     * @return  bool
245     */
246    public static function isRegistered($name)
247    {
248        return in_array($name, self::getRegistered());
249    }
250
251    /**
252     * Get all registered filer names.
253     *
254     * @return  array
255     */
256    public static function getRegistered()
257    {
258        return stream_get_filters();
259    }
260}
261
262/**
263 * Flex entity.
264 */
265Consistency::flexEntity('Hoa\Stream\Filter\Filter');
266