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