1<?php
2
3/**
4 * @see       https://github.com/laminas/laminas-feed for the canonical source repository
5 * @copyright https://github.com/laminas/laminas-feed/blob/master/COPYRIGHT.md
6 * @license   https://github.com/laminas/laminas-feed/blob/master/LICENSE.md New BSD License
7 */
8
9namespace Laminas\Feed\Writer;
10
11use Laminas\ServiceManager\AbstractPluginManager;
12use Laminas\ServiceManager\Exception\InvalidServiceException;
13use Laminas\ServiceManager\Factory\InvokableFactory;
14
15/**
16 * Plugin manager implementation for feed writer extensions
17 *
18 * Validation checks that we have an Entry, Feed, or Extension\AbstractRenderer.
19 */
20class ExtensionPluginManager extends AbstractPluginManager implements ExtensionManagerInterface
21{
22    /**
23     * Aliases for default set of extension classes
24     *
25     * @var array
26     */
27    protected $aliases = [
28        'atomrendererfeed'           => Extension\Atom\Renderer\Feed::class,
29        'atomRendererFeed'           => Extension\Atom\Renderer\Feed::class,
30        'AtomRendererFeed'           => Extension\Atom\Renderer\Feed::class,
31        'AtomRenderer\Feed'          => Extension\Atom\Renderer\Feed::class,
32        'Atom\Renderer\Feed'         => Extension\Atom\Renderer\Feed::class,
33        'contentrendererentry'       => Extension\Content\Renderer\Entry::class,
34        'contentRendererEntry'       => Extension\Content\Renderer\Entry::class,
35        'ContentRendererEntry'       => Extension\Content\Renderer\Entry::class,
36        'ContentRenderer\Entry'      => Extension\Content\Renderer\Entry::class,
37        'Content\Renderer\Entry'     => Extension\Content\Renderer\Entry::class,
38        'dublincorerendererentry'    => Extension\DublinCore\Renderer\Entry::class,
39        'dublinCoreRendererEntry'    => Extension\DublinCore\Renderer\Entry::class,
40        'DublinCoreRendererEntry'    => Extension\DublinCore\Renderer\Entry::class,
41        'DublinCoreRenderer\Entry'   => Extension\DublinCore\Renderer\Entry::class,
42        'DublinCore\Renderer\Entry'  => Extension\DublinCore\Renderer\Entry::class,
43        'dublincorerendererfeed'     => Extension\DublinCore\Renderer\Feed::class,
44        'dublinCoreRendererFeed'     => Extension\DublinCore\Renderer\Feed::class,
45        'DublinCoreRendererFeed'     => Extension\DublinCore\Renderer\Feed::class,
46        'DublinCoreRenderer\Feed'    => Extension\DublinCore\Renderer\Feed::class,
47        'DublinCore\Renderer\Feed'   => Extension\DublinCore\Renderer\Feed::class,
48        'googleplaypodcastentry'           => Extension\GooglePlayPodcast\Entry::class,
49        'googleplaypodcastEntry'           => Extension\GooglePlayPodcast\Entry::class,
50        'googlePlayPodcastEntry'           => Extension\GooglePlayPodcast\Entry::class,
51        'GooglePlayPodcastEntry'           => Extension\GooglePlayPodcast\Entry::class,
52        'Googleplaypodcast\Entry'          => Extension\GooglePlayPodcast\Entry::class,
53        'GooglePlayPodcast\Entry'          => Extension\GooglePlayPodcast\Entry::class,
54        'googleplaypodcastfeed'            => Extension\GooglePlayPodcast\Feed::class,
55        'googleplaypodcastFeed'            => Extension\GooglePlayPodcast\Feed::class,
56        'googlePlayPodcastFeed'            => Extension\GooglePlayPodcast\Feed::class,
57        'GooglePlayPodcastFeed'            => Extension\GooglePlayPodcast\Feed::class,
58        'Googleplaypodcast\Feed'           => Extension\GooglePlayPodcast\Feed::class,
59        'GooglePlayPodcast\Feed'           => Extension\GooglePlayPodcast\Feed::class,
60        'googleplaypodcastrendererentry'   => Extension\GooglePlayPodcast\Renderer\Entry::class,
61        'googleplaypodcastRendererEntry'   => Extension\GooglePlayPodcast\Renderer\Entry::class,
62        'googlePlayPodcastRendererEntry'   => Extension\GooglePlayPodcast\Renderer\Entry::class,
63        'GooglePlayPodcastRendererEntry'   => Extension\GooglePlayPodcast\Renderer\Entry::class,
64        'GoogleplaypodcastRenderer\Entry'  => Extension\GooglePlayPodcast\Renderer\Entry::class,
65        'GooglePlayPodcast\Renderer\Entry' => Extension\GooglePlayPodcast\Renderer\Entry::class,
66        'googleplaypodcastrendererfeed'    => Extension\GooglePlayPodcast\Renderer\Feed::class,
67        'googleplaypodcastRendererFeed'    => Extension\GooglePlayPodcast\Renderer\Feed::class,
68        'googlePlayPodcastRendererFeed'    => Extension\GooglePlayPodcast\Renderer\Feed::class,
69        'GooglePlayPodcastRendererFeed'    => Extension\GooglePlayPodcast\Renderer\Feed::class,
70        'GoogleplaypodcastRenderer\Feed'   => Extension\GooglePlayPodcast\Renderer\Feed::class,
71        'GooglePlayPodcast\Renderer\Feed'  => Extension\GooglePlayPodcast\Renderer\Feed::class,
72        'itunesentry'                => Extension\ITunes\Entry::class,
73        'itunesEntry'                => Extension\ITunes\Entry::class,
74        'iTunesEntry'                => Extension\ITunes\Entry::class,
75        'ItunesEntry'                => Extension\ITunes\Entry::class,
76        'Itunes\Entry'               => Extension\ITunes\Entry::class,
77        'ITunes\Entry'               => Extension\ITunes\Entry::class,
78        'itunesfeed'                 => Extension\ITunes\Feed::class,
79        'itunesFeed'                 => Extension\ITunes\Feed::class,
80        'iTunesFeed'                 => Extension\ITunes\Feed::class,
81        'ItunesFeed'                 => Extension\ITunes\Feed::class,
82        'Itunes\Feed'                => Extension\ITunes\Feed::class,
83        'ITunes\Feed'                => Extension\ITunes\Feed::class,
84        'itunesrendererentry'        => Extension\ITunes\Renderer\Entry::class,
85        'itunesRendererEntry'        => Extension\ITunes\Renderer\Entry::class,
86        'iTunesRendererEntry'        => Extension\ITunes\Renderer\Entry::class,
87        'ItunesRendererEntry'        => Extension\ITunes\Renderer\Entry::class,
88        'ItunesRenderer\Entry'       => Extension\ITunes\Renderer\Entry::class,
89        'ITunes\Renderer\Entry'      => Extension\ITunes\Renderer\Entry::class,
90        'itunesrendererfeed'         => Extension\ITunes\Renderer\Feed::class,
91        'itunesRendererFeed'         => Extension\ITunes\Renderer\Feed::class,
92        'iTunesRendererFeed'         => Extension\ITunes\Renderer\Feed::class,
93        'ItunesRendererFeed'         => Extension\ITunes\Renderer\Feed::class,
94        'ItunesRenderer\Feed'        => Extension\ITunes\Renderer\Feed::class,
95        'ITunes\Renderer\Feed'       => Extension\ITunes\Renderer\Feed::class,
96        'slashrendererentry'         => Extension\Slash\Renderer\Entry::class,
97        'slashRendererEntry'         => Extension\Slash\Renderer\Entry::class,
98        'SlashRendererEntry'         => Extension\Slash\Renderer\Entry::class,
99        'SlashRenderer\Entry'        => Extension\Slash\Renderer\Entry::class,
100        'Slash\Renderer\Entry'       => Extension\Slash\Renderer\Entry::class,
101        'threadingrendererentry'     => Extension\Threading\Renderer\Entry::class,
102        'threadingRendererEntry'     => Extension\Threading\Renderer\Entry::class,
103        'ThreadingRendererEntry'     => Extension\Threading\Renderer\Entry::class,
104        'ThreadingRenderer\Entry'    => Extension\Threading\Renderer\Entry::class,
105        'Threading\Renderer\Entry'   => Extension\Threading\Renderer\Entry::class,
106        'wellformedwebrendererentry' => Extension\WellFormedWeb\Renderer\Entry::class,
107        'wellFormedWebRendererEntry' => Extension\WellFormedWeb\Renderer\Entry::class,
108        'WellFormedWebRendererEntry' => Extension\WellFormedWeb\Renderer\Entry::class,
109        'WellFormedWebRenderer\Entry' => Extension\WellFormedWeb\Renderer\Entry::class,
110        'WellFormedWeb\Renderer\Entry' => Extension\WellFormedWeb\Renderer\Entry::class,
111
112        // Legacy Zend Framework aliases
113        // @codingStandardsIgnoreStart
114        \Zend\Feed\Writer\Extension\Atom\Renderer\Feed::class               => Extension\Atom\Renderer\Feed::class,
115        \Zend\Feed\Writer\Extension\Content\Renderer\Entry::class           => Extension\Content\Renderer\Entry::class,
116        \Zend\Feed\Writer\Extension\DublinCore\Renderer\Entry::class        => Extension\DublinCore\Renderer\Entry::class,
117        \Zend\Feed\Writer\Extension\DublinCore\Renderer\Feed::class         => Extension\DublinCore\Renderer\Feed::class,
118        \Zend\Feed\Writer\Extension\GooglePlayPodcast\Entry::class          => Extension\GooglePlayPodcast\Entry::class,
119        \Zend\Feed\Writer\Extension\GooglePlayPodcast\Feed::class           => Extension\GooglePlayPodcast\Feed::class,
120        \Zend\Feed\Writer\Extension\GooglePlayPodcast\Renderer\Entry::class => Extension\GooglePlayPodcast\Renderer\Entry::class,
121        \Zend\Feed\Writer\Extension\GooglePlayPodcast\Renderer\Feed::class  => Extension\GooglePlayPodcast\Renderer\Feed::class,
122        \Zend\Feed\Writer\Extension\ITunes\Entry::class                     => Extension\ITunes\Entry::class,
123        \Zend\Feed\Writer\Extension\ITunes\Feed::class                      => Extension\ITunes\Feed::class,
124        \Zend\Feed\Writer\Extension\ITunes\Renderer\Entry::class            => Extension\ITunes\Renderer\Entry::class,
125        \Zend\Feed\Writer\Extension\ITunes\Renderer\Feed::class             => Extension\ITunes\Renderer\Feed::class,
126        \Zend\Feed\Writer\Extension\Slash\Renderer\Entry::class             => Extension\Slash\Renderer\Entry::class,
127        \Zend\Feed\Writer\Extension\Threading\Renderer\Entry::class         => Extension\Threading\Renderer\Entry::class,
128        \Zend\Feed\Writer\Extension\WellFormedWeb\Renderer\Entry::class     => Extension\WellFormedWeb\Renderer\Entry::class,
129        // @codingStandardsIgnoreEnd
130
131        // v2 normalized FQCNs
132        'zendfeedwriterextensionatomrendererfeed' => Extension\Atom\Renderer\Feed::class,
133        'zendfeedwriterextensioncontentrendererentry' => Extension\Content\Renderer\Entry::class,
134        'zendfeedwriterextensiondublincorerendererentry' => Extension\DublinCore\Renderer\Entry::class,
135        'zendfeedwriterextensiondublincorerendererfeed' => Extension\DublinCore\Renderer\Feed::class,
136        'zendfeedwriterextensiongoogleplaypodcastentry' => Extension\GooglePlayPodcast\Entry::class,
137        'zendfeedwriterextensiongoogleplaypodcastfeed' => Extension\GooglePlayPodcast\Feed::class,
138        'zendfeedwriterextensiongoogleplaypodcastrendererentry' => Extension\GooglePlayPodcast\Renderer\Entry::class,
139        'zendfeedwriterextensiongoogleplaypodcastrendererfeed' => Extension\GooglePlayPodcast\Renderer\Feed::class,
140        'zendfeedwriterextensionitunesentry' => Extension\ITunes\Entry::class,
141        'zendfeedwriterextensionitunesfeed' => Extension\ITunes\Feed::class,
142        'zendfeedwriterextensionitunesrendererentry' => Extension\ITunes\Renderer\Entry::class,
143        'zendfeedwriterextensionitunesrendererfeed' => Extension\ITunes\Renderer\Feed::class,
144        'zendfeedwriterextensionslashrendererentry' => Extension\Slash\Renderer\Entry::class,
145        'zendfeedwriterextensionthreadingrendererentry' => Extension\Threading\Renderer\Entry::class,
146        'zendfeedwriterextensionwellformedwebrendererentry' => Extension\WellFormedWeb\Renderer\Entry::class,
147    ];
148
149    /**
150     * Factories for default set of extension classes
151     *
152     * @var array
153     */
154    protected $factories = [
155        Extension\Atom\Renderer\Feed::class           => InvokableFactory::class,
156        Extension\Content\Renderer\Entry::class       => InvokableFactory::class,
157        Extension\DublinCore\Renderer\Entry::class    => InvokableFactory::class,
158        Extension\DublinCore\Renderer\Feed::class     => InvokableFactory::class,
159        Extension\GooglePlayPodcast\Entry::class          => InvokableFactory::class,
160        Extension\GooglePlayPodcast\Feed::class           => InvokableFactory::class,
161        Extension\GooglePlayPodcast\Renderer\Entry::class => InvokableFactory::class,
162        Extension\GooglePlayPodcast\Renderer\Feed::class  => InvokableFactory::class,
163        Extension\ITunes\Entry::class                 => InvokableFactory::class,
164        Extension\ITunes\Feed::class                  => InvokableFactory::class,
165        Extension\ITunes\Renderer\Entry::class        => InvokableFactory::class,
166        Extension\ITunes\Renderer\Feed::class         => InvokableFactory::class,
167        Extension\Slash\Renderer\Entry::class         => InvokableFactory::class,
168        Extension\Threading\Renderer\Entry::class     => InvokableFactory::class,
169        Extension\WellFormedWeb\Renderer\Entry::class => InvokableFactory::class,
170        // Legacy (v2) due to alias resolution; canonical form of resolved
171        // alias is used to look up the factory, while the non-normalized
172        // resolved alias is used as the requested name passed to the factory.
173        'laminasfeedwriterextensionatomrendererfeed'           => InvokableFactory::class,
174        'laminasfeedwriterextensioncontentrendererentry'       => InvokableFactory::class,
175        'laminasfeedwriterextensiondublincorerendererentry'    => InvokableFactory::class,
176        'laminasfeedwriterextensiondublincorerendererfeed'     => InvokableFactory::class,
177        'laminasfeedwriterextensiongoogleplaypodcastentry'         => InvokableFactory::class,
178        'laminasfeedwriterextensiongoogleplaypodcastfeed'          => InvokableFactory::class,
179        'laminasfeedwriterextensiongoogleplaypodcastrendererentry' => InvokableFactory::class,
180        'laminasfeedwriterextensiongoogleplaypodcastrendererfeed'  => InvokableFactory::class,
181
182        'laminasfeedwriterextensionitunesentry'                => InvokableFactory::class,
183        'laminasfeedwriterextensionitunesfeed'                 => InvokableFactory::class,
184        'laminasfeedwriterextensionitunesrendererentry'        => InvokableFactory::class,
185        'laminasfeedwriterextensionitunesrendererfeed'         => InvokableFactory::class,
186        'laminasfeedwriterextensionslashrendererentry'         => InvokableFactory::class,
187        'laminasfeedwriterextensionthreadingrendererentry'     => InvokableFactory::class,
188        'laminasfeedwriterextensionwellformedwebrendererentry' => InvokableFactory::class,
189    ];
190
191    /**
192     * Do not share instances (v2)
193     *
194     * @var bool
195     */
196    protected $shareByDefault = false;
197
198    /**
199     * Do not share instances (v3)
200     *
201     * @var bool
202     */
203    protected $sharedByDefault = false;
204
205    /**
206     * Validate the plugin (v3)
207     *
208     * Checks that the extension loaded is of a valid type.
209     *
210     * @param  mixed $plugin
211     * @return void
212     * @throws InvalidServiceException if invalid
213     */
214    public function validate($plugin)
215    {
216        if ($plugin instanceof Extension\AbstractRenderer) {
217            // we're okay
218            return;
219        }
220
221        if ('Feed' === substr(get_class($plugin), -4)) {
222            // we're okay
223            return;
224        }
225
226        if ('Entry' === substr(get_class($plugin), -5)) {
227            // we're okay
228            return;
229        }
230
231        throw new InvalidServiceException(sprintf(
232            'Plugin of type %s is invalid; must implement %s\Extension\RendererInterface '
233            . 'or the classname must end in "Feed" or "Entry"',
234            is_object($plugin) ? get_class($plugin) : gettype($plugin),
235            __NAMESPACE__
236        ));
237    }
238
239    /**
240     * Validate plugin (v2)
241     *
242     * @param  mixed $plugin
243     * @return void
244     * @throws Exception\InvalidArgumentException when invalid
245     */
246    public function validatePlugin($plugin)
247    {
248        try {
249            $this->validate($plugin);
250        } catch (InvalidServiceException $e) {
251            throw new Exception\InvalidArgumentException(sprintf(
252                'Plugin of type %s is invalid; must implement %s\Extension\RendererInterface '
253                . 'or the classname must end in "Feed" or "Entry"',
254                is_object($plugin) ? get_class($plugin) : gettype($plugin),
255                __NAMESPACE__
256            ));
257        }
258    }
259}
260