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\Reader;
10
11use Laminas\ServiceManager\AbstractPluginManager;
12use Laminas\ServiceManager\Exception\InvalidServiceException;
13use Laminas\ServiceManager\Factory\InvokableFactory;
14
15/**
16 * Plugin manager implementation for feed reader extensions based on the
17 * AbstractPluginManager.
18 *
19 * Validation checks that we have an Extension\AbstractEntry or
20 * Extension\AbstractFeed.
21 */
22class ExtensionPluginManager extends AbstractPluginManager implements ExtensionManagerInterface
23{
24    /**
25     * Aliases for default set of extension classes
26     *
27     * @var array
28     */
29    protected $aliases = [
30        'atomentry'            => Extension\Atom\Entry::class,
31        'atomEntry'            => Extension\Atom\Entry::class,
32        'AtomEntry'            => Extension\Atom\Entry::class,
33        'Atom\Entry'           => Extension\Atom\Entry::class,
34        'atomfeed'             => Extension\Atom\Feed::class,
35        'atomFeed'             => Extension\Atom\Feed::class,
36        'AtomFeed'             => Extension\Atom\Feed::class,
37        'Atom\Feed'            => Extension\Atom\Feed::class,
38        'contententry'         => Extension\Content\Entry::class,
39        'contentEntry'         => Extension\Content\Entry::class,
40        'ContentEntry'         => Extension\Content\Entry::class,
41        'Content\Entry'        => Extension\Content\Entry::class,
42        'creativecommonsentry' => Extension\CreativeCommons\Entry::class,
43        'creativeCommonsEntry' => Extension\CreativeCommons\Entry::class,
44        'CreativeCommonsEntry' => Extension\CreativeCommons\Entry::class,
45        'CreativeCommons\Entry' => Extension\CreativeCommons\Entry::class,
46        'creativecommonsfeed'  => Extension\CreativeCommons\Feed::class,
47        'creativeCommonsFeed'  => Extension\CreativeCommons\Feed::class,
48        'CreativeCommonsFeed'  => Extension\CreativeCommons\Feed::class,
49        'CreativeCommons\Feed' => Extension\CreativeCommons\Feed::class,
50        'dublincoreentry'      => Extension\DublinCore\Entry::class,
51        'dublinCoreEntry'      => Extension\DublinCore\Entry::class,
52        'DublinCoreEntry'      => Extension\DublinCore\Entry::class,
53        'DublinCore\Entry'     => Extension\DublinCore\Entry::class,
54        'dublincorefeed'       => Extension\DublinCore\Feed::class,
55        'dublinCoreFeed'       => Extension\DublinCore\Feed::class,
56        'DublinCoreFeed'       => Extension\DublinCore\Feed::class,
57        'DublinCore\Feed'      => Extension\DublinCore\Feed::class,
58        'googleplaypodcastentry'  => Extension\GooglePlayPodcast\Entry::class,
59        'googlePlayPodcastEntry'  => Extension\GooglePlayPodcast\Entry::class,
60        'GooglePlayPodcastEntry'  => Extension\GooglePlayPodcast\Entry::class,
61        'GooglePlayPodcast\Entry' => Extension\GooglePlayPodcast\Entry::class,
62        'googleplaypodcastfeed'   => Extension\GooglePlayPodcast\Feed::class,
63        'googlePlayPodcastFeed'   => Extension\GooglePlayPodcast\Feed::class,
64        'GooglePlayPodcastFeed'   => Extension\GooglePlayPodcast\Feed::class,
65        'GooglePlayPodcast\Feed'  => Extension\GooglePlayPodcast\Feed::class,
66        'podcastentry'         => Extension\Podcast\Entry::class,
67        'podcastEntry'         => Extension\Podcast\Entry::class,
68        'PodcastEntry'         => Extension\Podcast\Entry::class,
69        'Podcast\Entry'        => Extension\Podcast\Entry::class,
70        'podcastfeed'          => Extension\Podcast\Feed::class,
71        'podcastFeed'          => Extension\Podcast\Feed::class,
72        'PodcastFeed'          => Extension\Podcast\Feed::class,
73        'Podcast\Feed'         => Extension\Podcast\Feed::class,
74        'slashentry'           => Extension\Slash\Entry::class,
75        'slashEntry'           => Extension\Slash\Entry::class,
76        'SlashEntry'           => Extension\Slash\Entry::class,
77        'Slash\Entry'          => Extension\Slash\Entry::class,
78        'syndicationfeed'      => Extension\Syndication\Feed::class,
79        'syndicationFeed'      => Extension\Syndication\Feed::class,
80        'SyndicationFeed'      => Extension\Syndication\Feed::class,
81        'Syndication\Feed'     => Extension\Syndication\Feed::class,
82        'threadentry'          => Extension\Thread\Entry::class,
83        'threadEntry'          => Extension\Thread\Entry::class,
84        'ThreadEntry'          => Extension\Thread\Entry::class,
85        'Thread\Entry'         => Extension\Thread\Entry::class,
86        'wellformedwebentry'   => Extension\WellFormedWeb\Entry::class,
87        'wellFormedWebEntry'   => Extension\WellFormedWeb\Entry::class,
88        'WellFormedWebEntry'   => Extension\WellFormedWeb\Entry::class,
89        'WellFormedWeb\Entry'  => Extension\WellFormedWeb\Entry::class,
90
91        // Legacy Zend Framework aliases
92        \Zend\Feed\Reader\Extension\Atom\Entry::class => Extension\Atom\Entry::class,
93        \Zend\Feed\Reader\Extension\Atom\Feed::class => Extension\Atom\Feed::class,
94        \Zend\Feed\Reader\Extension\Content\Entry::class => Extension\Content\Entry::class,
95        \Zend\Feed\Reader\Extension\CreativeCommons\Entry::class => Extension\CreativeCommons\Entry::class,
96        \Zend\Feed\Reader\Extension\CreativeCommons\Feed::class => Extension\CreativeCommons\Feed::class,
97        \Zend\Feed\Reader\Extension\DublinCore\Entry::class => Extension\DublinCore\Entry::class,
98        \Zend\Feed\Reader\Extension\DublinCore\Feed::class => Extension\DublinCore\Feed::class,
99        \Zend\Feed\Reader\Extension\GooglePlayPodcast\Entry::class => Extension\GooglePlayPodcast\Entry::class,
100        \Zend\Feed\Reader\Extension\GooglePlayPodcast\Feed::class => Extension\GooglePlayPodcast\Feed::class,
101        \Zend\Feed\Reader\Extension\Podcast\Entry::class => Extension\Podcast\Entry::class,
102        \Zend\Feed\Reader\Extension\Podcast\Feed::class => Extension\Podcast\Feed::class,
103        \Zend\Feed\Reader\Extension\Slash\Entry::class => Extension\Slash\Entry::class,
104        \Zend\Feed\Reader\Extension\Syndication\Feed::class => Extension\Syndication\Feed::class,
105        \Zend\Feed\Reader\Extension\Thread\Entry::class => Extension\Thread\Entry::class,
106        \Zend\Feed\Reader\Extension\WellFormedWeb\Entry::class => Extension\WellFormedWeb\Entry::class,
107
108        // v2 normalized FQCNs
109        'zendfeedreaderextensionatomentry' => Extension\Atom\Entry::class,
110        'zendfeedreaderextensionatomfeed' => Extension\Atom\Feed::class,
111        'zendfeedreaderextensioncontententry' => Extension\Content\Entry::class,
112        'zendfeedreaderextensioncreativecommonsentry' => Extension\CreativeCommons\Entry::class,
113        'zendfeedreaderextensioncreativecommonsfeed' => Extension\CreativeCommons\Feed::class,
114        'zendfeedreaderextensiondublincoreentry' => Extension\DublinCore\Entry::class,
115        'zendfeedreaderextensiondublincorefeed' => Extension\DublinCore\Feed::class,
116        'zendfeedreaderextensiongoogleplaypodcastentry' => Extension\GooglePlayPodcast\Entry::class,
117        'zendfeedreaderextensiongoogleplaypodcastfeed' => Extension\GooglePlayPodcast\Feed::class,
118        'zendfeedreaderextensionpodcastentry' => Extension\Podcast\Entry::class,
119        'zendfeedreaderextensionpodcastfeed' => Extension\Podcast\Feed::class,
120        'zendfeedreaderextensionslashentry' => Extension\Slash\Entry::class,
121        'zendfeedreaderextensionsyndicationfeed' => Extension\Syndication\Feed::class,
122        'zendfeedreaderextensionthreadentry' => Extension\Thread\Entry::class,
123        'zendfeedreaderextensionwellformedwebentry' => Extension\WellFormedWeb\Entry::class,
124    ];
125
126    /**
127     * Factories for default set of extension classes
128     *
129     * @var array
130     */
131    protected $factories = [
132        Extension\Atom\Entry::class            => InvokableFactory::class,
133        Extension\Atom\Feed::class             => InvokableFactory::class,
134        Extension\Content\Entry::class         => InvokableFactory::class,
135        Extension\CreativeCommons\Entry::class => InvokableFactory::class,
136        Extension\CreativeCommons\Feed::class  => InvokableFactory::class,
137        Extension\DublinCore\Entry::class      => InvokableFactory::class,
138        Extension\DublinCore\Feed::class       => InvokableFactory::class,
139        Extension\GooglePlayPodcast\Entry::class => InvokableFactory::class,
140        Extension\GooglePlayPodcast\Feed::class  => InvokableFactory::class,
141        Extension\Podcast\Entry::class         => InvokableFactory::class,
142        Extension\Podcast\Feed::class          => InvokableFactory::class,
143        Extension\Slash\Entry::class           => InvokableFactory::class,
144        Extension\Syndication\Feed::class      => InvokableFactory::class,
145        Extension\Thread\Entry::class          => InvokableFactory::class,
146        Extension\WellFormedWeb\Entry::class   => InvokableFactory::class,
147        // Legacy (v2) due to alias resolution; canonical form of resolved
148        // alias is used to look up the factory, while the non-normalized
149        // resolved alias is used as the requested name passed to the factory.
150        'laminasfeedreaderextensionatomentry'            => InvokableFactory::class,
151        'laminasfeedreaderextensionatomfeed'             => InvokableFactory::class,
152        'laminasfeedreaderextensioncontententry'         => InvokableFactory::class,
153        'laminasfeedreaderextensioncreativecommonsentry' => InvokableFactory::class,
154        'laminasfeedreaderextensioncreativecommonsfeed'  => InvokableFactory::class,
155        'laminasfeedreaderextensiondublincoreentry'      => InvokableFactory::class,
156        'laminasfeedreaderextensiondublincorefeed'       => InvokableFactory::class,
157        'laminasfeedreaderextensiongoogleplaypodcastentry' => InvokableFactory::class,
158        'laminasfeedreaderextensiongoogleplaypodcastfeed'  => InvokableFactory::class,
159        'laminasfeedreaderextensionpodcastentry'         => InvokableFactory::class,
160        'laminasfeedreaderextensionpodcastfeed'          => InvokableFactory::class,
161        'laminasfeedreaderextensionslashentry'           => InvokableFactory::class,
162        'laminasfeedreaderextensionsyndicationfeed'      => InvokableFactory::class,
163        'laminasfeedreaderextensionthreadentry'          => InvokableFactory::class,
164        'laminasfeedreaderextensionwellformedwebentry'   => InvokableFactory::class,
165    ];
166
167    /**
168     * Do not share instances (v2)
169     *
170     * @var bool
171     */
172    protected $shareByDefault = false;
173
174    /**
175     * Do not share instances (v3)
176     *
177     * @var bool
178     */
179    protected $sharedByDefault = false;
180
181    /**
182     * Validate the plugin
183     *
184     * Checks that the extension loaded is of a valid type.
185     *
186     * @param  mixed $plugin
187     * @return void
188     * @throws Exception\InvalidArgumentException if invalid
189     */
190    public function validate($plugin)
191    {
192        if ($plugin instanceof Extension\AbstractEntry
193            || $plugin instanceof Extension\AbstractFeed
194        ) {
195            // we're okay
196            return;
197        }
198
199        throw new InvalidServiceException(sprintf(
200            'Plugin of type %s is invalid; must implement %s\Extension\AbstractFeed '
201            . 'or %s\Extension\AbstractEntry',
202            is_object($plugin) ? get_class($plugin) : gettype($plugin),
203            __NAMESPACE__,
204            __NAMESPACE__
205        ));
206    }
207
208    /**
209     * Validate the plugin (v2)
210     *
211     * @param  mixed $plugin
212     * @return void
213     * @throws Exception\InvalidArgumentException if invalid
214     */
215    public function validatePlugin($plugin)
216    {
217        try {
218            $this->validate($plugin);
219        } catch (InvalidServiceException $e) {
220            throw new Exception\InvalidArgumentException(sprintf(
221                'Plugin of type %s is invalid; must implement %s\Extension\AbstractFeed '
222                . 'or %s\Extension\AbstractEntry',
223                is_object($plugin) ? get_class($plugin) : gettype($plugin),
224                __NAMESPACE__,
225                __NAMESPACE__
226            ));
227        }
228    }
229}
230