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     * @return void
95     */
96    public function setOriginalSourceUri($uri)
97    {
98        $this->originalSourceUri = $uri;
99    }
100
101    /**
102     * Get an original source URI for the feed being parsed. Returns null if
103     * unset or the feed was not imported from a URI.
104     *
105     * @return null|string
106     */
107    public function getOriginalSourceUri()
108    {
109        return $this->originalSourceUri;
110    }
111
112    /**
113     * Get the number of feed entries.
114     * Required by the Iterator interface.
115     *
116     * @return int
117     */
118    public function count()
119    {
120        return count($this->entries);
121    }
122
123    /**
124     * Return the current entry
125     *
126     * @return Entry\AbstractEntry
127     */
128    public function current()
129    {
130        if (0 === strpos($this->getType(), 'rss')) {
131            $reader = new Entry\Rss($this->entries[$this->key()], $this->key(), $this->getType());
132        } else {
133            $reader = new Entry\Atom($this->entries[$this->key()], $this->key(), $this->getType());
134        }
135
136        $reader->setXpath($this->xpath);
137
138        return $reader;
139    }
140
141    /**
142     * Get the DOM
143     *
144     * @return DOMDocument
145     */
146    public function getDomDocument()
147    {
148        return $this->domDocument;
149    }
150
151    /**
152     * Get the Feed's encoding
153     *
154     * @return string
155     */
156    public function getEncoding()
157    {
158        $assumed = $this->getDomDocument()->encoding;
159        if (empty($assumed)) {
160            $assumed = 'UTF-8';
161        }
162        return $assumed;
163    }
164
165    /**
166     * Get feed as xml
167     *
168     * @return string
169     */
170    public function saveXml()
171    {
172        return $this->getDomDocument()->saveXML();
173    }
174
175    /**
176     * Get the DOMElement representing the items/feed element
177     *
178     * @return DOMElement
179     */
180    public function getElement()
181    {
182        return $this->getDomDocument()->documentElement;
183    }
184
185    /**
186     * Get the DOMXPath object for this feed
187     *
188     * @return DOMXPath
189     */
190    public function getXpath()
191    {
192        return $this->xpath;
193    }
194
195    /**
196     * Get the feed type
197     *
198     * @return string
199     */
200    public function getType()
201    {
202        return $this->data['type'];
203    }
204
205    /**
206     * Return the current feed key
207     *
208     * @return int
209     */
210    public function key()
211    {
212        return $this->entriesKey;
213    }
214
215    /**
216     * Move the feed pointer forward
217     */
218    public function next()
219    {
220        ++$this->entriesKey;
221    }
222
223    /**
224     * Reset the pointer in the feed object
225     */
226    public function rewind()
227    {
228        $this->entriesKey = 0;
229    }
230
231    /**
232     * Check to see if the iterator is still valid
233     *
234     * @return bool
235     */
236    public function valid()
237    {
238        return 0 <= $this->entriesKey && $this->entriesKey < $this->count();
239    }
240
241    public function getExtensions()
242    {
243        return $this->extensions;
244    }
245
246    public function __call($method, $args)
247    {
248        foreach ($this->extensions as $extension) {
249            if (method_exists($extension, $method)) {
250                return call_user_func_array([$extension, $method], $args);
251            }
252        }
253        throw new Exception\BadMethodCallException(
254            'Method: ' . $method . ' does not exist and could not be located on a registered Extension'
255        );
256    }
257
258    /**
259     * Return an Extension object with the matching name (postfixed with _Feed)
260     *
261     * @param  string $name
262     * @return Extension\AbstractFeed
263     */
264    public function getExtension($name)
265    {
266        if (array_key_exists($name . '\Feed', $this->extensions)) {
267            return $this->extensions[$name . '\Feed'];
268        }
269        return;
270    }
271
272    protected function loadExtensions()
273    {
274        $all     = Reader::getExtensions();
275        $manager = Reader::getExtensionManager();
276        $feed    = $all['feed'];
277        foreach ($feed as $extension) {
278            if (in_array($extension, $all['core'])) {
279                continue;
280            }
281            $plugin = $manager->get($extension);
282            $plugin->setDomDocument($this->getDomDocument());
283            $plugin->setType($this->data['type']);
284            $plugin->setXpath($this->xpath);
285            $this->extensions[$extension] = $plugin;
286        }
287    }
288
289    /**
290     * Read all entries to the internal entries array
291     */
292    abstract protected function indexEntries();
293
294    /**
295     * Register the default namespaces for the current feed format
296     */
297    abstract protected function registerNamespaces();
298}
299