Overview

Namespaces

  • Alpha
    • Controller
      • Front
    • Exception
    • Model
      • Type
    • Task
    • Util
      • Backup
      • Cache
      • Code
        • Highlight
        • Metric
      • Config
      • Convertor
      • Email
      • Extension
      • Feed
      • File
      • Graph
      • Helper
      • Http
        • Filter
        • Session
      • Image
      • Logging
      • Search
      • Security
    • View
      • Renderer
        • Html
        • Json
      • Widget

Classes

  • Atom
  • Feed
  • RSS
  • RSS2
  • Overview
  • Namespace
  • Class
  • Tree
  1: <?php
  2: 
  3: namespace Alpha\Util\Feed;
  4: 
  5: use Alpha\Util\Logging\Logger;
  6: use Alpha\Exception\IllegalArguementException;
  7: use Alpha\Model\ActiveRecord;
  8: use DOMDocument;
  9: use DOMElement;
 10: 
 11: /**
 12:  * Base feed class for generating syndication feeds.
 13:  *
 14:  * @since 1.0
 15:  *
 16:  * @author John Collins <dev@alphaframework.org>
 17:  * @license http://www.opensource.org/licenses/bsd-license.php The BSD License
 18:  * @copyright Copyright (c) 2015, John Collins (founder of Alpha Framework).
 19:  * All rights reserved.
 20:  *
 21:  * <pre>
 22:  * Redistribution and use in source and binary forms, with or
 23:  * without modification, are permitted provided that the
 24:  * following conditions are met:
 25:  *
 26:  * * Redistributions of source code must retain the above
 27:  *   copyright notice, this list of conditions and the
 28:  *   following disclaimer.
 29:  * * Redistributions in binary form must reproduce the above
 30:  *   copyright notice, this list of conditions and the
 31:  *   following disclaimer in the documentation and/or other
 32:  *   materials provided with the distribution.
 33:  * * Neither the name of the Alpha Framework nor the names
 34:  *   of its contributors may be used to endorse or promote
 35:  *   products derived from this software without specific
 36:  *   prior written permission.
 37:  *
 38:  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 39:  * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 40:  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 41:  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 42:  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 43:  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 44:  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 45:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 46:  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 47:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 48:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 49:  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 50:  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 51:  * </pre>
 52:  */
 53: abstract class Feed
 54: {
 55:     /**
 56:      * The DOMDocument object used to create the feed.
 57:      *
 58:      * @var DOMDocument
 59:      *
 60:      * @since 1.0
 61:      */
 62:     protected $rssDoc;
 63: 
 64:     /**
 65:      * The DOMElement object used to hold the item or entry elements.
 66:      *
 67:      * @var DOMElement
 68:      *
 69:      * @since 1.0
 70:      */
 71:     protected $docElement;
 72: 
 73:     /**
 74:      * Holds the DOMElement to which metadata is added for the feed.
 75:      *
 76:      * @var DOMElement
 77:      *
 78:      * @since 1.0
 79:      */
 80:     protected $root;
 81: 
 82:     /**
 83:      * The actual root tag used in each feed type.
 84:      *
 85:      * @var string
 86:      *
 87:      * @since 1.0
 88:      */
 89:     protected $rootTag;
 90: 
 91:     /**
 92:      * An array of feed items.
 93:      *
 94:      * @var array
 95:      *
 96:      * @since 1.0
 97:      */
 98:     protected $items;
 99: 
100:     /**
101:      * If the feed format has a channel or not.
102:      *
103:      * @var bool
104:      *
105:      * @since 1.0
106:      */
107:     protected $hasChannel = true;
108: 
109:     /**
110:      * Maps the tags to the feed-specific tags.
111:      *
112:      * @var array
113:      *
114:      * @since 1.0
115:      */
116:     protected $tagMap = array('item' => 'item', 'feeddesc' => 'description', 'itemdesc' => 'description');
117: 
118:     /**
119:      * The BO which we will serve up in this feed.
120:      *
121:      * @var Alpha\Model\ActiveRecord
122:      *
123:      * @since 1.0
124:      */
125:     private $BO;
126: 
127:     /**
128:      * An array containing BO field names -> RSS field name mappings.
129:      *
130:      * @var array
131:      *
132:      * @since 1.0
133:      */
134:     protected $fieldNameMappings;
135: 
136:     /**
137:      * The XML namespace to use in the generated feed.
138:      *
139:      * @var string
140:      */
141:     protected $nameSpace;
142: 
143:     /**
144:      * Trace logger.
145:      *
146:      * @var Alpha\Util\Loggin\Logger
147:      *
148:      * @since 1.0
149:      */
150:     private static $logger = null;
151: 
152:     /**
153:      * The constructor.
154:      *
155:      * @param string $BOName      The fully-qualifified classname of the BO to render a feed for.
156:      * @param string $title       The title of the feed.
157:      * @param string $url         The base URL for the feed.
158:      * @param string $description The description of the feed.
159:      * @param string $pubDate     The publish date, only used in Atom feeds.
160:      * @param int    $id          The feed id, only used in Atom feeds.
161:      * @param int    $limit       The amount of items to render in the feed.
162:      *
163:      * @throws IllegalArguementException
164:      *
165:      * @since 1.0
166:      */
167:     public function __construct($BOName, $title, $url, $description, $pubDate = null, $id = null, $limit = 10)
168:     {
169:         self::$logger = new Logger('Feed');
170:         self::$logger->debug('>>__construct(BOName=['.$BOName.'], title=['.$title.'], url=['.$url.'], description=['.$description.'], pubDate=['.$pubDate.'], id=['.$id.'], limit=['.$limit.'])');
171: 
172:         $this->rssDoc = new DOMDocument();
173:         $this->rssDoc->loadXML($this->rootTag);
174:         $this->docElement = $this->rssDoc->documentElement;
175: 
176:         if (!class_exists($BOName)) {
177:             throw new IllegalArguementException('Unable to load the class definition for the class ['.$BOName.'] while trying to generate a feed!');
178:         }
179: 
180:         $this->BO = new $BOName();
181: 
182:         if ($this->hasChannel) {
183:             $root = $this->createFeedElement('channel');
184:             $this->root = $this->docElement->appendChild($root);
185:         } else {
186:             $this->root = $this->docElement;
187:         }
188: 
189:         $this->createRSSNode('feed', $this->root, $title, $url, $description, $pubDate, $id);
190: 
191:         self::$logger->debug('<<__construct');
192:     }
193: 
194:     /**
195:      * Method to load all of the BO items to the feed from the database, from the newest to the
196:      * $limit provided.
197:      *
198:      * @param int    $limit  The amount of items to render in the feed.
199:      * @param string $sortBy The name of the field to sort the feed by.
200:      *
201:      * @since 1.0
202:      */
203:     public function loadBOs($limit, $sortBy)
204:     {
205:         $BOs = $this->BO->loadAll(0, $limit, $sortBy, 'DESC');
206: 
207:         ActiveRecord::disconnect();
208: 
209:         foreach ($BOs as $BO) {
210:             $this->addBO($BO);
211:         }
212:     }
213: 
214:     /**
215:      * Method for adding a BO to the current feed.
216:      *
217:      * @param Alpha\Model\ActiveRecord $BO
218:      */
219:     public function addBO($BO)
220:     {
221:         $title = $BO->get($this->fieldNameMappings['title']);
222:         $url = $BO->get($this->fieldNameMappings['url']);
223: 
224:         if (isset($this->fieldNameMappings['description'])) {
225:             $description = $BO->get($this->fieldNameMappings['description']);
226:         } else {
227:             $description = '';
228:         }
229: 
230:         if (isset($this->fieldNameMappings['pubDate'])) {
231:             $dateTS = strtotime($BO->get($this->fieldNameMappings['pubDate']));
232:             $pubDate = date(DATE_ATOM, $dateTS);
233:         } else {
234:             $pubDate = '';
235:         }
236: 
237:         if (isset($this->fieldNameMappings['id'])) {
238:             $id = $BO->get($this->fieldNameMappings['id']);
239:         } else {
240:             $id = '';
241:         }
242: 
243:         $this->addItem($title, $url, $description, $pubDate, $id);
244:     }
245: 
246:     /**
247:      * Method for mapping BO fieldnames to feed field names.
248:      *
249:      * @param string $title       The title of the feed.
250:      * @param string $url         The base URL for the feed.
251:      * @param string $description The description of the feed.
252:      * @param string $pubDate     The publish date, only used in Atom feeds.
253:      * @param int    $id          The feed id, only used in Atom feeds.
254:      *
255:      * @since 1.0
256:      */
257:     public function setFieldMappings($title, $url, $description = null, $pubDate = null, $id = null)
258:     {
259:         $this->fieldNameMappings = array(
260:             'title' => $title,
261:             'url' => $url,
262:         );
263: 
264:         if (isset($description)) {
265:             $this->fieldNameMappings['description'] = $description;
266:         }
267: 
268:         if (isset($pubDate)) {
269:             $this->fieldNameMappings['pubDate'] = $pubDate;
270:         }
271: 
272:         if (isset($id)) {
273:             $this->fieldNameMappings['id'] = $id;
274:         }
275:     }
276: 
277:     /**
278:      * Method for creating a new feed element.
279:      *
280:      * @param string $name  The name of the element.
281:      * @param string $value The value of the element.
282:      *
283:      * @return DOMElement
284:      *
285:      * @since 1.0
286:      */
287:     protected function createFeedElement($name, $value = null)
288:     {
289:         $value = htmlspecialchars($value);
290: 
291:         if ($this->nameSpace == null) {
292:             return $this->rssDoc->createElement($name, $value);
293:         } else {
294:             return $this->rssDoc->createElementNS($this->nameSpace, $name, $value);
295:         }
296:     }
297: 
298:     /**
299:      * Method for creating link elements (note that Atom has a different format).
300:      *
301:      * @param DOMElement $parent The parent element.
302:      * @param string     $url    The URL for the link.
303:      *
304:      * @since 1.0
305:      */
306:     protected function createLink($parent, $url)
307:     {
308:         $link = $this->createFeedElement('link', $url);
309:         $parent->appendChild($link);
310:     }
311: 
312:     /**
313:      * Method for creating an RSS node with a title, url and description.
314:      *
315:      * @param int        $type        Can be either (item|feed) to indicate the type of node we are creating.
316:      * @param DOMElement $parent      The parent element.
317:      * @param string     $title       The title of the feed.
318:      * @param string     $url         The base URL for the feed.
319:      * @param string     $description The description of the feed.
320:      * @param string     $pubDate     The publish date, only used in Atom feeds.
321:      * @param int        $id          The feed id, only used in Atom feeds.
322:      *
323:      * @since 1.0
324:      *
325:      * @throws Alpha\Exception\IllegalArguementException
326:      */
327:     protected function createRSSNode($type, $parent, $title, $url, $description, $pubDate = null, $id = null)
328:     {
329:         $this->createLink($parent, $url);
330:         $title = $this->createFeedElement('title', $title);
331:         $parent->appendChild($title);
332: 
333:         if ($type == 'item') {
334:             $titletag = $this->tagMap['itemdesc'];
335:         } elseif ($type == 'feed') {
336:             $titletag = $this->tagMap['feeddesc'];
337:         } else {
338:             throw new IllegalArguementException('The type paramater ['.$type.'] provided is invalid!');
339:         }
340: 
341:         $description = $this->createFeedElement($titletag, $description);
342:         $parent->appendChild($description);
343: 
344:         // id elements and updated elements are just for Atom!
345:         if ($id != null) {
346:             $idnode = $this->createFeedElement('id', $id);
347:             $parent->appendChild($idnode);
348:         }
349: 
350:         if ($pubDate != null) {
351:             $datenode = $this->createFeedElement('updated', $pubDate);
352:             $parent->appendChild($datenode);
353:         }
354:     }
355: 
356:     /**
357:      * Method for adding an item to a feed.
358:      *
359:      * @param string $title       The title of the feed.
360:      * @param string $url         The base URL for the feed.
361:      * @param string $description The description of the feed.
362:      * @param string $pubDate     The publish date, only used in Atom feeds.
363:      * @param int    $id          The feed id, only used in Atom feeds.
364:      *
365:      * @since 1.0
366:      */
367:     protected function addItem($title, $url, $description = null, $pubDate = null, $id = null)
368:     {
369:         $item = $this->createFeedElement($this->tagMap['item']);
370: 
371:         if ($this->docElement->appendChild($item)) {
372:             $this->createRSSNode('item', $item, $title, $url, $description, $pubDate, $id);
373:         }
374:     }
375: 
376:     /**
377:      * Returns the formatted XML for the feed as a string.
378:      *
379:      * @return string
380:      *
381:      * @since 1.0
382:      */
383:     public function render()
384:     {
385:         if ($this->rssDoc) {
386:             $this->rssDoc->formatOutput = true;
387: 
388:             return $this->rssDoc->saveXML();
389:         } else {
390:             return '';
391:         }
392:     }
393: }
394: 
Alpha Framework 2.0.4 API Documentation API documentation generated by ApiGen 2.8.0