1<?php
2
3/**
4 * SimplePie
5 *
6 * A PHP-Based RSS and Atom Feed Framework.
7 * Takes the hard work out of managing a complete RSS/Atom solution.
8 *
9 * Copyright (c) 2004-2022, Ryan Parman, Sam Sneddon, Ryan McCue, and contributors
10 * All rights reserved.
11 *
12 * Redistribution and use in source and binary forms, with or without modification, are
13 * permitted provided that the following conditions are met:
14 *
15 * 	* Redistributions of source code must retain the above copyright notice, this list of
16 * 	  conditions and the following disclaimer.
17 *
18 * 	* Redistributions in binary form must reproduce the above copyright notice, this list
19 * 	  of conditions and the following disclaimer in the documentation and/or other materials
20 * 	  provided with the distribution.
21 *
22 * 	* Neither the name of the SimplePie Team nor the names of its contributors may be used
23 * 	  to endorse or promote products derived from this software without specific prior
24 * 	  written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
27 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
28 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
29 * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
33 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 * POSSIBILITY OF SUCH DAMAGE.
35 *
36 * @package SimplePie
37 * @copyright 2004-2016 Ryan Parman, Sam Sneddon, Ryan McCue
38 * @author Ryan Parman
39 * @author Sam Sneddon
40 * @author Ryan McCue
41 * @link http://simplepie.org/ SimplePie
42 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
43 */
44
45namespace SimplePie;
46
47use SimplePie\Content\Type\Sniffer;
48use SimplePie\Parse\Date;
49use SimplePie\XML\Declaration\Parser as DeclarationParser;
50
51/**
52 * Handles creating objects and calling methods
53 *
54 * Access this via {@see \SimplePie\SimplePie::get_registry()}
55 *
56 * @package SimplePie
57 */
58class Registry
59{
60    /**
61     * Default class mapping
62     *
63     * Overriding classes *must* subclass these.
64     *
65     * @var array<class-string, class-string>
66     */
67    protected $default = [
68        Cache::class => Cache::class,
69        Locator::class => Locator::class,
70        Parser::class => Parser::class,
71        File::class => File::class,
72        Sanitize::class => Sanitize::class,
73        Item::class => Item::class,
74        Author::class => Author::class,
75        Category::class => Category::class,
76        Enclosure::class => Enclosure::class,
77        Caption::class => Caption::class,
78        Copyright::class => Copyright::class,
79        Credit::class => Credit::class,
80        Rating::class => Rating::class,
81        Restriction::class => Restriction::class,
82        Sniffer::class => Sniffer::class,
83        Source::class => Source::class,
84        Misc::class => Misc::class,
85        DeclarationParser::class => DeclarationParser::class,
86        Date::class => Date::class,
87    ];
88
89    /**
90     * Class mapping
91     *
92     * @see register()
93     * @var array
94     */
95    protected $classes = [];
96
97    /**
98     * Legacy classes
99     *
100     * @see register()
101     * @var array<class-string>
102     */
103    protected $legacy = [];
104
105    /**
106     * Legacy types
107     *
108     * @see register()
109     * @var array<string, class-string>
110     */
111    private $legacyTypes = [
112        'Cache' => Cache::class,
113        'Locator' => Locator::class,
114        'Parser' => Parser::class,
115        'File' => File::class,
116        'Sanitize' => Sanitize::class,
117        'Item' => Item::class,
118        'Author' => Author::class,
119        'Category' => Category::class,
120        'Enclosure' => Enclosure::class,
121        'Caption' => Caption::class,
122        'Copyright' => Copyright::class,
123        'Credit' => Credit::class,
124        'Rating' => Rating::class,
125        'Restriction' => Restriction::class,
126        'Content_Type_Sniffer' => Sniffer::class,
127        'Source' => Source::class,
128        'Misc' => Misc::class,
129        'XML_Declaration_Parser' => DeclarationParser::class,
130        'Parse_Date' => Date::class,
131    ];
132
133    /**
134     * Constructor
135     *
136     * No-op
137     */
138    public function __construct()
139    {
140    }
141
142    /**
143     * Register a class
144     *
145     * @param string $type See {@see $default} for names
146     * @param class-string $class Class name, must subclass the corresponding default
147     * @param bool $legacy Whether to enable legacy support for this class
148     * @return bool Successfulness
149     */
150    public function register($type, $class, $legacy = false)
151    {
152        if (array_key_exists($type, $this->legacyTypes)) {
153            // trigger_error(sprintf('"%s"(): Using argument #1 ($type) with value "%s" is deprecated since SimplePie 1.8.0, use class-string "%s" instead.', __METHOD__, $type, $this->legacyTypes[$type]), \E_USER_DEPRECATED);
154
155            $type = $this->legacyTypes[$type];
156        }
157
158        if (!array_key_exists($type, $this->default)) {
159            return false;
160        }
161
162        if (!class_exists($class)) {
163            return false;
164        }
165
166        /** @var string */
167        $base_class = $this->default[$type];
168
169        if (!is_subclass_of($class, $base_class)) {
170            return false;
171        }
172
173        $this->classes[$type] = $class;
174
175        if ($legacy) {
176            $this->legacy[] = $class;
177        }
178
179        return true;
180    }
181
182    /**
183     * Get the class registered for a type
184     *
185     * Where possible, use {@see create()} or {@see call()} instead
186     *
187     * @template T
188     * @param class-string<T> $type
189     * @return class-string<T>|null
190     */
191    public function get_class($type)
192    {
193        if (array_key_exists($type, $this->legacyTypes)) {
194            // trigger_error(sprintf('"%s"(): Using argument #1 ($type) with value "%s" is deprecated since SimplePie 1.8.0, use class-string "%s" instead.', __METHOD__, $type, $this->legacyTypes[$type]), \E_USER_DEPRECATED);
195
196            $type = $this->legacyTypes[$type];
197        }
198
199        if (!array_key_exists($type, $this->default)) {
200            return null;
201        }
202
203        $class = $this->default[$type];
204
205        if (array_key_exists($type, $this->classes)) {
206            $class = $this->classes[$type];
207        }
208
209        return $class;
210    }
211
212    /**
213     * Create a new instance of a given type
214     *
215     * @template T class-string $type
216     * @param class-string<T> $type
217     * @param array $parameters Parameters to pass to the constructor
218     * @return T Instance of class
219     */
220    public function &create($type, $parameters = [])
221    {
222        $class = $this->get_class($type);
223
224        if (!method_exists($class, '__construct')) {
225            $instance = new $class();
226        } else {
227            $reflector = new \ReflectionClass($class);
228            $instance = $reflector->newInstanceArgs($parameters);
229        }
230
231        if ($instance instanceof RegistryAware) {
232            $instance->set_registry($this);
233        } elseif (method_exists($instance, 'set_registry')) {
234            trigger_error(sprintf('Using the method "set_registry()" without implementing "%s" is deprecated since SimplePie 1.8.0, implement "%s" in "%s".', RegistryAware::class, RegistryAware::class, $class), \E_USER_DEPRECATED);
235            $instance->set_registry($this);
236        }
237        return $instance;
238    }
239
240    /**
241     * Call a static method for a type
242     *
243     * @param class-string $type
244     * @param string $method
245     * @param array $parameters
246     * @return mixed
247     */
248    public function &call($type, $method, $parameters = [])
249    {
250        $class = $this->get_class($type);
251
252        if (in_array($class, $this->legacy)) {
253            switch ($type) {
254                case Cache::class:
255                    // For backwards compatibility with old non-static
256                    // Cache::create() methods in PHP < 8.0.
257                    // No longer supported as of PHP 8.0.
258                    if ($method === 'get_handler') {
259                        $result = @call_user_func_array([$class, 'create'], $parameters);
260                        return $result;
261                    }
262                    break;
263            }
264        }
265
266        $result = call_user_func_array([$class, $method], $parameters);
267        return $result;
268    }
269}
270
271class_alias('SimplePie\Registry', 'SimplePie_Registry');
272