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 DOMDocument;
12use DOMElement;
13use DOMXPath;
14
15/**
16 * @deprecated This (abstract) class is deprecated. Use \Laminas\Feed\Reader\Feed\AbstractFeed instead.
17 */
18abstract class AbstractFeed implements Feed\FeedInterface
19{
20    /**
21     * Parsed feed data
22     *
23     * @var array
24     */
25    protected $data = [];
26
27    /**
28     * Parsed feed data in the shape of a DOMDocument
29     *
30     * @var DOMDocument
31     */
32    protected $domDocument;
33
34    /**
35     * An array of parsed feed entries
36     *
37     * @var array
38     */
39    protected $entries = [];
40
41    /**
42     * A pointer for the iterator to keep track of the entries array
43     *
44     * @var int
45     */
46    protected $entriesKey = 0;
47
48    /**
49     * The base XPath query used to retrieve feed data
50     *
51     * @var DOMXPath
52     */
53    protected $xpath;
54
55    /**
56     * Array of loaded extensions
57     *
58     * @var array
59     */
60    protected $extensions = [];
61
62    /**
63     * Original Source URI (set if imported from a URI)
64     *
65     * @var string
66     */
67    protected $originalSourceUri;
68
69    /**
70     * @param DOMDocument $domDocument The DOM object for the feed's XML
71     * @param null|string $type Feed type
72     */
73    public function __construct(DOMDocument $domDocument, $type = null)
74    {
75        $this->domDocument = $domDocument;
76        $this->xpath       = new DOMXPath($this->domDocument);
77
78        if ($type !== null) {
79            $this->data['type'] = $type;
80        } else {
81            $this->data['type'] = Reader::detectType($this->domDocument);
82        }
83        $this->registerNamespaces();
84        $this->indexEntries();
85        $this->loadExtensions();
86    }
87
88    /**
89     * Set an original source URI for the feed being parsed. This value
90     * is returned from getFeedLink() method if the feed does not carry
91     * a self-referencing URI.
92     *
93     * @param string $uri
94     */
95    public function setOriginalSourceUri($uri)
96    {
97        $this->originalSourceUri = $uri;
98    }
99
100    /**
101     * Get an original source URI for the feed being parsed. Returns null if
102     * unset or the feed was not imported from a URI.
103     *
104     * @return null|string
105     */
106    public function getOriginalSourceUri()
107    {
108        return $this->originalSourceUri;
109    }
110
111    /**
112     * Get the number of feed entries.
113     * Required by the Iterator interface.
114     *
115     * @return int
116     */
117    public function count()
118    {
119        return count($this->entries);
120    }
121
122    /**
123     * Return the current entry
124     *
125     * @return Entry\AbstractEntry
126     */
127    public function current()
128    {
129        if (0 === strpos($this->getType(), 'rss')) {
130            $reader = new Entry\Rss($this->entries[$this->key()], $this->key(), $this->getType());
131        } else {
132            $reader = new Entry\Atom($this->entries[$this->key()], $this->key(), $this->getType());
133        }
134
135        $reader->setXpath($this->xpath);
136
137        return $reader;
138    }
139
140    /**
141     * Get the DOM
142     *
143     * @return DOMDocument
144     */
145    public function getDomDocument()
146    {
147        return $this->domDocument;
148    }
149
150    /**
151     * Get the Feed's encoding
152     *
153     * @return string
154     */
155    public function getEncoding()
156    {
157        $assumed = $this->getDomDocument()->encoding;
158        if (empty($assumed)) {
159            $assumed = 'UTF-8';
160        }
161        return $assumed;
162    }
163
164    /**
165     * Get feed as xml
166     *
167     * @return string
168     */
169    public function saveXml()
170    {
171        return $this->getDomDocument()->saveXML();
172    }
173
174    /**
175     * Get the DOMElement representing the items/feed element
176     *
177     * @return DOMElement
178     */
179    public function getElement()
180    {
181        return $this->getDomDocument()->documentElement;
182    }
183
184    /**
185     * Get the DOMXPath object for this feed
186     *
187     * @return DOMXPath
188     */
189    public function getXpath()
190    {
191        return $this->xpath;
192    }
193
194    /**
195     * Get the feed type
196     *
197     * @return string
198     */
199    public function getType()
200    {
201        return $this->data['type'];
202    }
203
204    /**
205     * Return the current feed key
206     *
207     * @return int
208     */
209    public function key()
210    {
211        return $this->entriesKey;
212    }
213
214    /**
215     * Move the feed pointer forward
216     */
217    public function next()
218    {
219        ++$this->entriesKey;
220    }
221
222    /**
223     * Reset the pointer in the feed object
224     */
225    public function rewind()
226    {
227        $this->entriesKey = 0;
228    }
229
230    /**
231     * Check to see if the iterator is still valid
232     *
233     * @return bool
234     */
235    public function valid()
236    {
237        return 0 <= $this->entriesKey && $this->entriesKey < $this->count();
238    }
239
240    public function getExtensions()
241    {
242        return $this->extensions;
243    }
244
245    public function __call($method, $args)
246    {
247        foreach ($this->extensions as $extension) {
248            if (method_exists($extension, $method)) {
249                return call_user_func_array([$extension, $method], $args);
250            }
251        }
252        throw new Exception\BadMethodCallException(
253            'Method: ' . $method . ' does not exist and could not be located on a registered Extension'
254        );
255    }
256
257    /**
258     * Return an Extension object with the matching name (postfixed with _Feed)
259     *
260     * @param  string $name
261     * @return Extension\AbstractFeed
262     */
263    public function getExtension($name)
264    {
265        if (array_key_exists($name . '\Feed', $this->extensions)) {
266            return $this->extensions[$name . '\Feed'];
267        }
268        return;
269    }
270
271    protected function loadExtensions()
272    {
273        $all     = Reader::getExtensions();
274        $manager = Reader::getExtensionManager();
275        $feed    = $all['feed'];
276        foreach ($feed as $extension) {
277            if (in_array($extension, $all['core'])) {
278                continue;
279            }
280            $plugin = $manager->get($extension);
281            $plugin->setDomDocument($this->getDomDocument());
282            $plugin->setType($this->data['type']);
283            $plugin->setXpath($this->xpath);
284            $this->extensions[$extension] = $plugin;
285        }
286    }
287
288    /**
289     * Read all entries to the internal entries array
290     */
291    abstract protected function indexEntries();
292
293    /**
294     * Register the default namespaces for the current feed format
295     */
296    abstract protected function registerNamespaces();
297}
298