361 lines
		
	
	
		
			7.5 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			361 lines
		
	
	
		
			7.5 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| <?php
 | |
| /**
 | |
|  * @package     FrameworkOnFramework
 | |
|  * @subpackage  view
 | |
|  * @copyright   Copyright (C) 2010-2016 Nicholas K. Dionysopoulos / Akeeba Ltd. All rights reserved.
 | |
|  * @license     GNU General Public License version 2 or later; see LICENSE.txt
 | |
|  */
 | |
| // Protect from unauthorized access
 | |
| defined('F0F_INCLUDED') or die;
 | |
| 
 | |
| /**
 | |
|  * FrameworkOnFramework JSON View class. Renders the data as a JSON object or
 | |
|  * array. It can optionally output HAL links as well.
 | |
|  *
 | |
|  * @package  FrameworkOnFramework
 | |
|  * @since    2.0
 | |
|  */
 | |
| class F0FViewJson extends F0FViewHtml
 | |
| {
 | |
| 	/**
 | |
| 	 * When set to true we'll add hypermedia to the output, implementing the
 | |
| 	 * HAL specification (http://stateless.co/hal_specification.html)
 | |
| 	 *
 | |
| 	 * @var   boolean
 | |
| 	 */
 | |
| 	public $useHypermedia = false;
 | |
| 
 | |
| 	/**
 | |
| 	 * Public constructor
 | |
| 	 *
 | |
| 	 * @param   array  $config  The component's configuration array
 | |
| 	 */
 | |
| 	public function __construct($config = array())
 | |
| 	{
 | |
| 		parent::__construct($config);
 | |
| 
 | |
| 		if (isset($config['use_hypermedia']))
 | |
| 		{
 | |
| 			$this->useHypermedia = (bool) $config['use_hypermedia'];
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * The event which runs when we are displaying the record list JSON view
 | |
| 	 *
 | |
| 	 * @param   string  $tpl  The view sub-template to use
 | |
| 	 *
 | |
| 	 * @return  boolean  True to allow display of the view
 | |
| 	 */
 | |
| 	protected function onDisplay($tpl = null)
 | |
| 	{
 | |
| 		// Load the model
 | |
| 		$model = $this->getModel();
 | |
| 
 | |
| 		$items = $model->getItemList();
 | |
| 		$this->items = $items;
 | |
| 
 | |
| 		$document = F0FPlatform::getInstance()->getDocument();
 | |
| 
 | |
| 		if ($document instanceof JDocument)
 | |
| 		{
 | |
| 			if ($this->useHypermedia)
 | |
| 			{
 | |
| 				$document->setMimeEncoding('application/hal+json');
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				$document->setMimeEncoding('application/json');
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		if (is_null($tpl))
 | |
| 		{
 | |
| 			$tpl = 'json';
 | |
| 		}
 | |
| 
 | |
| 		F0FPlatform::getInstance()->setErrorHandling(E_ALL, 'ignore');
 | |
| 
 | |
| 		$hasFailed = false;
 | |
| 
 | |
| 		try
 | |
| 		{
 | |
| 			$result = $this->loadTemplate($tpl, true);
 | |
| 
 | |
| 			if ($result instanceof Exception)
 | |
| 			{
 | |
| 				$hasFailed = true;
 | |
| 			}
 | |
| 		}
 | |
| 		catch (Exception $e)
 | |
| 		{
 | |
| 			$hasFailed = true;
 | |
| 		}
 | |
| 
 | |
| 		if ($hasFailed)
 | |
| 		{
 | |
| 			// Default JSON behaviour in case the template isn't there!
 | |
| 			if ($this->useHypermedia)
 | |
| 			{
 | |
| 				$haldocument = $this->_createDocumentWithHypermedia($items, $model);
 | |
| 				$json = $haldocument->render('json');
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				$json = json_encode($items);
 | |
| 			}
 | |
| 
 | |
| 			// JSONP support
 | |
| 			$callback = $this->input->get('callback', null, 'raw');
 | |
| 
 | |
| 			if (!empty($callback))
 | |
| 			{
 | |
| 				echo $callback . '(' . $json . ')';
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				$defaultName = $this->input->getCmd('view', 'joomla');
 | |
| 				$filename = $this->input->getCmd('basename', $defaultName);
 | |
| 
 | |
| 				$document->setName($filename);
 | |
| 				echo $json;
 | |
| 			}
 | |
| 
 | |
| 			return false;
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			echo $result;
 | |
| 
 | |
| 			return false;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * The event which runs when we are displaying a single item JSON view
 | |
| 	 *
 | |
| 	 * @param   string  $tpl  The view sub-template to use
 | |
| 	 *
 | |
| 	 * @return  boolean  True to allow display of the view
 | |
| 	 */
 | |
| 	protected function onRead($tpl = null)
 | |
| 	{
 | |
| 		$model = $this->getModel();
 | |
| 
 | |
| 		$item = $model->getItem();
 | |
| 		$this->item = $item;
 | |
| 
 | |
| 		$document = F0FPlatform::getInstance()->getDocument();
 | |
| 
 | |
| 		if ($document instanceof JDocument)
 | |
| 		{
 | |
| 			if ($this->useHypermedia)
 | |
| 			{
 | |
| 				$document->setMimeEncoding('application/hal+json');
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				$document->setMimeEncoding('application/json');
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		if (is_null($tpl))
 | |
| 		{
 | |
| 			$tpl = 'json';
 | |
| 		}
 | |
| 
 | |
|     	F0FPlatform::getInstance()->setErrorHandling(E_ALL, 'ignore');
 | |
| 
 | |
| 		$hasFailed = false;
 | |
| 
 | |
| 		try
 | |
| 		{
 | |
| 			$result = $this->loadTemplate($tpl, true);
 | |
| 
 | |
|             if ($result instanceof Exception)
 | |
|             {
 | |
|                 $hasFailed = true;
 | |
|             }
 | |
| 		}
 | |
| 		catch (Exception $e)
 | |
| 		{
 | |
| 			$hasFailed = true;
 | |
| 		}
 | |
| 
 | |
| 		if ($hasFailed)
 | |
| 		{
 | |
| 			// Default JSON behaviour in case the template isn't there!
 | |
| 
 | |
| 			if ($this->useHypermedia)
 | |
| 			{
 | |
| 				$haldocument = $this->_createDocumentWithHypermedia($item, $model);
 | |
| 				$json = $haldocument->render('json');
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				$json = json_encode($item);
 | |
| 			}
 | |
| 
 | |
| 			// JSONP support
 | |
| 			$callback = $this->input->get('callback', null);
 | |
| 
 | |
| 			if (!empty($callback))
 | |
| 			{
 | |
| 				echo $callback . '(' . $json . ')';
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				$defaultName = $this->input->getCmd('view', 'joomla');
 | |
| 				$filename = $this->input->getCmd('basename', $defaultName);
 | |
| 				$document->setName($filename);
 | |
| 				echo $json;
 | |
| 			}
 | |
| 
 | |
| 			return false;
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			echo $result;
 | |
| 
 | |
| 			return false;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Creates a F0FHalDocument using the provided data
 | |
| 	 *
 | |
| 	 * @param   array     $data   The data to put in the document
 | |
| 	 * @param   F0FModel  $model  The model of this view
 | |
| 	 *
 | |
| 	 * @return  F0FHalDocument  A HAL-enabled document
 | |
| 	 */
 | |
| 	protected function _createDocumentWithHypermedia($data, $model = null)
 | |
| 	{
 | |
| 		// Create a new HAL document
 | |
| 
 | |
| 		if (is_array($data))
 | |
| 		{
 | |
| 			$count = count($data);
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			$count = null;
 | |
| 		}
 | |
| 
 | |
| 		if ($count == 1)
 | |
| 		{
 | |
| 			reset($data);
 | |
| 			$document = new F0FHalDocument(end($data));
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			$document = new F0FHalDocument($data);
 | |
| 		}
 | |
| 
 | |
| 		// Create a self link
 | |
| 		$uri = (string) (JUri::getInstance());
 | |
| 		$uri = $this->_removeURIBase($uri);
 | |
| 		$uri = JRoute::_($uri);
 | |
| 		$document->addLink('self', new F0FHalLink($uri));
 | |
| 
 | |
| 		// Create relative links in a record list context
 | |
| 
 | |
| 		if (is_array($data) && ($model instanceof F0FModel))
 | |
| 		{
 | |
| 			$pagination = $model->getPagination();
 | |
| 
 | |
| 			if ($pagination->get('pages.total') > 1)
 | |
| 			{
 | |
| 				// Try to guess URL parameters and create a prototype URL
 | |
| 				// NOTE: You are better off specialising this method
 | |
| 				$protoUri = $this->_getPrototypeURIForPagination();
 | |
| 
 | |
| 				// The "first" link
 | |
| 				$uri = clone $protoUri;
 | |
| 				$uri->setVar('limitstart', 0);
 | |
| 				$uri = JRoute::_((string) $uri);
 | |
| 
 | |
| 				$document->addLink('first', new F0FHalLink($uri));
 | |
| 
 | |
| 				// Do we need a "prev" link?
 | |
| 
 | |
| 				if ($pagination->get('pages.current') > 1)
 | |
| 				{
 | |
| 					$prevPage = $pagination->get('pages.current') - 1;
 | |
| 					$limitstart = ($prevPage - 1) * $pagination->limit;
 | |
| 					$uri = clone $protoUri;
 | |
| 					$uri->setVar('limitstart', $limitstart);
 | |
| 					$uri = JRoute::_((string) $uri);
 | |
| 
 | |
| 					$document->addLink('prev', new F0FHalLink($uri));
 | |
| 				}
 | |
| 
 | |
| 				// Do we need a "next" link?
 | |
| 
 | |
| 				if ($pagination->get('pages.current') < $pagination->get('pages.total'))
 | |
| 				{
 | |
| 					$nextPage = $pagination->get('pages.current') + 1;
 | |
| 					$limitstart = ($nextPage - 1) * $pagination->limit;
 | |
| 					$uri = clone $protoUri;
 | |
| 					$uri->setVar('limitstart', $limitstart);
 | |
| 					$uri = JRoute::_((string) $uri);
 | |
| 
 | |
| 					$document->addLink('next', new F0FHalLink($uri));
 | |
| 				}
 | |
| 
 | |
| 				// The "last" link?
 | |
| 				$lastPage = $pagination->get('pages.total');
 | |
| 				$limitstart = ($lastPage - 1) * $pagination->limit;
 | |
| 				$uri = clone $protoUri;
 | |
| 				$uri->setVar('limitstart', $limitstart);
 | |
| 				$uri = JRoute::_((string) $uri);
 | |
| 
 | |
| 				$document->addLink('last', new F0FHalLink($uri));
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		return $document;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Convert an absolute URI to a relative one
 | |
| 	 *
 | |
| 	 * @param   string  $uri  The URI to convert
 | |
| 	 *
 | |
| 	 * @return  string  The relative URL
 | |
| 	 */
 | |
| 	protected function _removeURIBase($uri)
 | |
| 	{
 | |
| 		static $root = null, $rootlen = 0;
 | |
| 
 | |
| 		if (is_null($root))
 | |
| 		{
 | |
| 			$root = rtrim(F0FPlatform::getInstance()->URIbase(), '/');
 | |
| 			$rootlen = strlen($root);
 | |
| 		}
 | |
| 
 | |
| 		if (substr($uri, 0, $rootlen) == $root)
 | |
| 		{
 | |
| 			$uri = substr($uri, $rootlen);
 | |
| 		}
 | |
| 
 | |
| 		return ltrim($uri, '/');
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Returns a JUri instance with a prototype URI used as the base for the
 | |
| 	 * other URIs created by the JSON renderer
 | |
| 	 *
 | |
| 	 * @return  JUri  The prototype JUri instance
 | |
| 	 */
 | |
| 	protected function _getPrototypeURIForPagination()
 | |
| 	{
 | |
| 		$protoUri = new JUri('index.php');
 | |
| 		$protoUri->setQuery($this->input->getData());
 | |
| 		$protoUri->delVar('savestate');
 | |
| 		$protoUri->delVar('base_path');
 | |
| 
 | |
| 		return $protoUri;
 | |
| 	}
 | |
| }
 |