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;
|
|
}
|
|
}
|