* * use \FeedWriter\Feed; * use \FeedWriter\View\Atom; * * // Here's an array of arrays describing some blog posts. These could also * // be objects with properties like $blog_posts->writer. * * $blog_posts = [ * [ 'date_created' => '2013-02-14', 'writer' => 'Brennen Bearnes', 'text' => 'Hate.' ], * [ 'date_created' => '2013-07-04', 'writer' => 'Brennen Bearnes', 'text' => 'Explosions.' ], * [ 'date_created' => '2013-08-31', 'writer' => 'Brennen Bearnes', 'text' => 'A feed thingy.' ], * ]; * * // Here's a map that explains how to find the properties we need for our * // view: * $entry_from_post = [ * 'date' => 'date_created', * 'author' => 'writer', * 'content' => 'text' * ]; * * $feed = new Feed($blog_posts, $entry_from_post, ['atom' => new Atom]); * * // If everything went ok, views are now available as properties of the feed. * if (! $feed->error()) * echo $feed->atom->render(); * else * echo 'error: ' . $feed->error(); * * * * @param $source mixed iterator or array * @param $map array describing mapping of fields to fields * @param $views array one or more views to generate */ public function __construct ($source, array $map, array $views) { if (is_array($source)) $iter = new ArrayIterator($source); else $iter = $source; $this->setIter($iter); $this->setViewsAndMap($views, $map); $this->spin(); } /** * Explode if anybody tries to set a property directly. */ public function __set ($name, $view) { throw new Exception("You can't directly set properties on Feed. See documentation for constructor."); } /** * Get a view. */ public function __get ($name) { return $this->_views[$name]; } /** * Is a given view set? */ public function __isset ($name) { return isset($this->_views[$name]); } /** * Stash views and map, making sure that the map provides for anything * the view explicitly requires. */ protected function setViewsAndMap (array $views, array $map) { if (! count($views)) throw new Exception('Feed requires that at least one view instance be passed in)'); if (! is_array($map)) throw new Exception('$map must be an array'); if (! count($map)) throw new Exception('$map must provide values'); // Validate map for each view: foreach ($views as $name => $view) { if (! isset($view->require)) continue; foreach ($view->require as $field) { if (! isset($map[ $field ])) { throw new Exception('$map should provide a mapping for ' . $field); } } } $this->_views = $views; $this->_map = $map; } protected function setIter (Iterator $iter) { if (! ($iter instanceof Iterator)) throw new Exception('$iter must be an iterator'); $this->_iter = $iter; } /** * Do the business of handing off values to views. */ protected function spin () { $output_item = (object)[]; while ($this->_iter->valid()) { $input_item = $this->_iter->current(); if (is_array($input_item)) $input_item = (object)$input_item; foreach ($this->_map as $output_key => &$input_key) { if (is_string($input_key)) { // shorthand for "use this field on the object for the value" if (isset($input_item->$input_key)) $output_item->$output_key = $input_item->$input_key; else throw new Exception("unable to access $input_key on input item: " . print_r($input_item, 1)); } elseif (is_callable($input_key)) { // if we have a function, pass it the item and expect it to // return a value for our output key $output_item->$output_key = $input_key($input_item); } } foreach ($this->_views as $name => $view) { $view->collect($output_item); } $this->_iter->next(); } } }