primo commit
This commit is contained in:
276
libraries/fof30/View/DataView/Csv.php
Normal file
276
libraries/fof30/View/DataView/Csv.php
Normal file
@ -0,0 +1,276 @@
|
||||
<?php
|
||||
/**
|
||||
* @package FOF
|
||||
* @copyright Copyright (c)2010-2021 Nicholas K. Dionysopoulos / Akeeba Ltd
|
||||
* @license GNU General Public License version 2, or later
|
||||
*/
|
||||
|
||||
namespace FOF30\View\DataView;
|
||||
|
||||
defined('_JEXEC') || die;
|
||||
|
||||
use Exception;
|
||||
use FOF30\Container\Container;
|
||||
use FOF30\Model\DataModel;
|
||||
use FOF30\View\Exception\AccessForbidden;
|
||||
use Joomla\CMS\Document\Document;
|
||||
|
||||
class Csv extends Html implements DataViewInterface
|
||||
{
|
||||
/**
|
||||
* Should I produce a CSV header row.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
protected $csvHeader = true;
|
||||
|
||||
/**
|
||||
* The filename of the downloaded CSV file.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $csvFilename = null;
|
||||
|
||||
/**
|
||||
* The columns to include in the CSV output. If it's empty it will be ignored.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $csvFields = [];
|
||||
|
||||
|
||||
/**
|
||||
* Public constructor. Instantiates a F0FViewCsv object.
|
||||
*
|
||||
*
|
||||
* @param Container $container The container we belong to
|
||||
* @param array $config The configuration overrides for the view
|
||||
*/
|
||||
public function __construct(Container $container, array $config = [])
|
||||
{
|
||||
parent::__construct($container, $config);
|
||||
|
||||
if (array_key_exists('csv_header', $config))
|
||||
{
|
||||
$this->csvHeader = $config['csv_header'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->csvHeader = $this->input->getBool('csv_header', true);
|
||||
}
|
||||
|
||||
if (array_key_exists('csv_filename', $config))
|
||||
{
|
||||
$this->csvFilename = $config['csv_filename'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->csvFilename = $this->input->getString('csv_filename', '');
|
||||
}
|
||||
|
||||
if (empty($this->csvFilename))
|
||||
{
|
||||
$view = $this->input->getCmd('view', 'cpanel');
|
||||
$view = $this->container->inflector->pluralize($view);
|
||||
$this->csvFilename = strtolower($view) . '.csv';
|
||||
}
|
||||
|
||||
if (array_key_exists('csv_fields', $config))
|
||||
{
|
||||
$this->csvFields = $config['csv_fields'];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides the default method to execute and display a template script.
|
||||
* Instead of loadTemplate is uses loadAnyTemplate.
|
||||
*
|
||||
* @param string $tpl The name of the template file to parse
|
||||
*
|
||||
* @return boolean True on success
|
||||
*
|
||||
* @throws Exception When the layout file is not found
|
||||
*/
|
||||
public function display($tpl = null)
|
||||
{
|
||||
$eventName = 'onBefore' . ucfirst($this->doTask);
|
||||
$this->triggerEvent($eventName, [$tpl]);
|
||||
|
||||
// Load the model
|
||||
/** @var DataModel $model */
|
||||
$model = $this->getModel();
|
||||
|
||||
$items = $model->get();
|
||||
$this->items = $items;
|
||||
|
||||
$platform = $this->container->platform;
|
||||
$document = $platform->getDocument();
|
||||
|
||||
if ($document instanceof Document)
|
||||
{
|
||||
$document->setMimeEncoding('text/csv');
|
||||
}
|
||||
|
||||
$platform->setHeader('Pragma', 'public');
|
||||
$platform->setHeader('Expires', '0');
|
||||
|
||||
/**
|
||||
* This construct is required to work around bad quality hosts who blacklist files based on broken malware
|
||||
* scanners. The only way to beat them is... wait for it... write our software using the same obscure constructs
|
||||
* actual malware is using to evade these broken malware scanners. The irony is not lost on me.
|
||||
*/
|
||||
$xo = substr("revenge", 0, 3);
|
||||
$xoxo = substr("calibrate", 1, 2);
|
||||
$platform->setHeader('Cache-Control', 'must-' . $xo . $xoxo . 'idate, post-check=0, pre-check=0');
|
||||
|
||||
$platform->setHeader('Cache-Control', 'public', false);
|
||||
$platform->setHeader('Content-Description', 'File Transfer');
|
||||
$platform->setHeader('Content-Disposition', 'attachment; filename="' . $this->csvFilename . '"');
|
||||
|
||||
if (is_null($tpl))
|
||||
{
|
||||
$tpl = 'csv';
|
||||
}
|
||||
|
||||
$hasFailed = false;
|
||||
|
||||
try
|
||||
{
|
||||
$result = $this->loadTemplate($tpl, true);
|
||||
|
||||
if ($result instanceof Exception)
|
||||
{
|
||||
$hasFailed = true;
|
||||
}
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
$hasFailed = true;
|
||||
}
|
||||
|
||||
if (!$hasFailed)
|
||||
{
|
||||
echo $result;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Default CSV behaviour in case the template isn't there!
|
||||
if (count($items) === 0)
|
||||
{
|
||||
throw new AccessForbidden;
|
||||
}
|
||||
|
||||
$item = $items->last();
|
||||
$keys = $item->getData();
|
||||
$keys = array_keys($keys);
|
||||
|
||||
reset($items);
|
||||
|
||||
if (!empty($this->csvFields))
|
||||
{
|
||||
$temp = [];
|
||||
|
||||
foreach ($this->csvFields as $f)
|
||||
{
|
||||
$exist = false;
|
||||
|
||||
// If we have a dot and it isn't part of the field name, we are dealing with relations
|
||||
if (!$model->hasField($f) && strpos($f, '.'))
|
||||
{
|
||||
$methods = explode('.', $f);
|
||||
$object = $item;
|
||||
// Let's see if the relation exists
|
||||
foreach ($methods as $method)
|
||||
{
|
||||
if (isset($object->$method) || property_exists($object, $method))
|
||||
{
|
||||
$exist = true;
|
||||
$object = $object->$method;
|
||||
}
|
||||
else
|
||||
{
|
||||
$exist = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (in_array($f, $keys))
|
||||
{
|
||||
$temp[] = $f;
|
||||
}
|
||||
elseif ($exist)
|
||||
{
|
||||
$temp[] = $f;
|
||||
}
|
||||
}
|
||||
|
||||
$keys = $temp;
|
||||
}
|
||||
|
||||
if ($this->csvHeader)
|
||||
{
|
||||
$csv = [];
|
||||
|
||||
foreach ($keys as $k)
|
||||
{
|
||||
$k = str_replace('"', '""', $k);
|
||||
$k = str_replace("\r", '\\r', $k);
|
||||
$k = str_replace("\n", '\\n', $k);
|
||||
$k = '"' . $k . '"';
|
||||
|
||||
$csv[] = $k;
|
||||
}
|
||||
|
||||
echo implode(",", $csv) . "\r\n";
|
||||
}
|
||||
|
||||
foreach ($items as $item)
|
||||
{
|
||||
$csv = [];
|
||||
|
||||
foreach ($keys as $k)
|
||||
{
|
||||
// If our key contains a dot and it isn't part of the field name, we are dealing with relations
|
||||
if (!$model->hasField($k) && strpos($k, '.'))
|
||||
{
|
||||
$methods = explode('.', $k);
|
||||
$v = $item;
|
||||
|
||||
foreach ($methods as $method)
|
||||
{
|
||||
$v = $v->$method;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$v = $item->$k;
|
||||
}
|
||||
|
||||
if (is_array($v))
|
||||
{
|
||||
$v = 'Array';
|
||||
}
|
||||
elseif (is_object($v))
|
||||
{
|
||||
$v = 'Object';
|
||||
}
|
||||
|
||||
$v = str_replace('"', '""', $v);
|
||||
$v = str_replace("\r", '\\r', $v);
|
||||
$v = str_replace("\n", '\\n', $v);
|
||||
$v = '"' . $v . '"';
|
||||
|
||||
$csv[] = $v;
|
||||
}
|
||||
|
||||
echo implode(",", $csv) . "\r\n";
|
||||
}
|
||||
}
|
||||
|
||||
$eventName = 'onAfter' . ucfirst($this->doTask);
|
||||
$this->triggerEvent($eventName, [$tpl]);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
146
libraries/fof30/View/DataView/DataViewInterface.php
Normal file
146
libraries/fof30/View/DataView/DataViewInterface.php
Normal file
@ -0,0 +1,146 @@
|
||||
<?php
|
||||
/**
|
||||
* @package FOF
|
||||
* @copyright Copyright (c)2010-2021 Nicholas K. Dionysopoulos / Akeeba Ltd
|
||||
* @license GNU General Public License version 2, or later
|
||||
*/
|
||||
|
||||
namespace FOF30\View\DataView;
|
||||
|
||||
defined('_JEXEC') || die;
|
||||
|
||||
use Exception;
|
||||
use FOF30\Container\Container;
|
||||
use Joomla\CMS\Pagination\Pagination;
|
||||
use stdClass;
|
||||
|
||||
interface DataViewInterface
|
||||
{
|
||||
/**
|
||||
* Determines if the current Joomla! version and your current table support AJAX-powered drag and drop reordering.
|
||||
* If they do, it will set up the drag & drop reordering feature.
|
||||
*
|
||||
* @return boolean|array False if not supported, otherwise a table with necessary information (saveOrder: should
|
||||
* you enable DnD reordering; orderingColumn: which column has the ordering information).
|
||||
*/
|
||||
public function hasAjaxOrderingSupport();
|
||||
|
||||
/**
|
||||
* Returns the internal list of useful variables to the benefit of header fields.
|
||||
*
|
||||
* @return stdClass
|
||||
*/
|
||||
public function getLists();
|
||||
|
||||
/**
|
||||
* Returns a reference to the permissions object of this view
|
||||
*
|
||||
* @return stdClass
|
||||
*/
|
||||
public function getPerms();
|
||||
|
||||
/**
|
||||
* Returns a reference to the pagination object of this view
|
||||
*
|
||||
* @return Pagination
|
||||
*/
|
||||
public function getPagination();
|
||||
|
||||
/**
|
||||
* Method to get the view name
|
||||
*
|
||||
* The model name by default parsed using the classname, or it can be set
|
||||
* by passing a $config['name'] in the class constructor
|
||||
*
|
||||
* @return string The name of the model
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function getName();
|
||||
|
||||
/**
|
||||
* Returns a reference to the container attached to this View
|
||||
*
|
||||
* @return Container
|
||||
*/
|
||||
public function &getContainer();
|
||||
|
||||
/**
|
||||
* Escapes a value for output in a view script.
|
||||
*
|
||||
* @param mixed $var The output to escape.
|
||||
*
|
||||
* @return string The escaped value.
|
||||
*/
|
||||
public function escape($var);
|
||||
|
||||
/**
|
||||
* Returns the task being rendered by the view
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getTask();
|
||||
|
||||
/**
|
||||
* Get the layout.
|
||||
*
|
||||
* @return string The layout name
|
||||
*/
|
||||
public function getLayout();
|
||||
|
||||
/**
|
||||
* Add a JS script file to the page generated by the CMS.
|
||||
*
|
||||
* There are three combinations of defer and async (see http://www.w3schools.com/tags/att_script_defer.asp):
|
||||
* * $defer false, $async true: The script is executed asynchronously with the rest of the page
|
||||
* (the script will be executed while the page continues the parsing)
|
||||
* * $defer true, $async false: The script is executed when the page has finished parsing.
|
||||
* * $defer false, $async false. (default) The script is loaded and executed immediately. When it finishes
|
||||
* loading the browser continues parsing the rest of the page.
|
||||
*
|
||||
* When you are using $defer = true there is no guarantee about the load order of the scripts. Whichever
|
||||
* script loads first will be executed first. The order they appear on the page is completely irrelevant.
|
||||
*
|
||||
* @param string $uri A path definition understood by parsePath, e.g. media://com_example/js/foo.js
|
||||
* @param string $version (optional) Version string to be added to the URL
|
||||
* @param string $type MIME type of the script
|
||||
* @param boolean $defer Adds the defer attribute, see above
|
||||
* @param boolean $async Adds the async attribute, see above
|
||||
*
|
||||
* @return $this Self, for chaining
|
||||
*/
|
||||
public function addJavascriptFile($uri, $version = null, $type = 'text/javascript', $defer = false, $async = false);
|
||||
|
||||
/**
|
||||
* Adds an inline JavaScript script to the page header
|
||||
*
|
||||
* @param string $script The script content to add
|
||||
* @param string $type The MIME type of the script
|
||||
*
|
||||
* @return $this Self, for chaining
|
||||
*/
|
||||
public function addJavascriptInline($script, $type = 'text/javascript');
|
||||
|
||||
/**
|
||||
* Add a CSS file to the page generated by the CMS
|
||||
*
|
||||
* @param string $uri A path definition understood by parsePath, e.g. media://com_example/css/foo.css
|
||||
* @param string $version (optional) Version string to be added to the URL
|
||||
* @param string $type MIME type of the stylesheeet
|
||||
* @param string $media Media target definition of the style sheet, e.g. "screen"
|
||||
* @param array $attribs Array of attributes
|
||||
*
|
||||
* @return $this Self, for chaining
|
||||
*/
|
||||
public function addCssFile($uri, $version = null, $type = 'text/css', $media = null, $attribs = []);
|
||||
|
||||
/**
|
||||
* Adds an inline stylesheet (inline CSS) to the page header
|
||||
*
|
||||
* @param string $css The stylesheet content to add
|
||||
* @param string $type The MIME type of the script
|
||||
*
|
||||
* @return $this Self, for chaining
|
||||
*/
|
||||
public function addCssInline($css, $type = 'text/css');
|
||||
}
|
||||
176
libraries/fof30/View/DataView/Html.php
Normal file
176
libraries/fof30/View/DataView/Html.php
Normal file
@ -0,0 +1,176 @@
|
||||
<?php
|
||||
/**
|
||||
* @package FOF
|
||||
* @copyright Copyright (c)2010-2021 Nicholas K. Dionysopoulos / Akeeba Ltd
|
||||
* @license GNU General Public License version 2, or later
|
||||
*/
|
||||
|
||||
namespace FOF30\View\DataView;
|
||||
|
||||
defined('_JEXEC') || die;
|
||||
|
||||
use Exception;
|
||||
use FOF30\Render\RenderInterface;
|
||||
use Joomla\CMS\Application\SiteApplication;
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\Language\Text;
|
||||
|
||||
class Html extends Raw implements DataViewInterface
|
||||
{
|
||||
/** @var bool Should I set the page title in the front-end of the site? */
|
||||
public $setFrontendPageTitle = false;
|
||||
|
||||
/** @var string The translation key for the default page title */
|
||||
public $defaultPageTitle = null;
|
||||
|
||||
public function setPageTitle()
|
||||
{
|
||||
if (!$this->container->platform->isFrontend())
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
/** @var SiteApplication $app */
|
||||
$app = Factory::getApplication();
|
||||
$document = Factory::getDocument();
|
||||
$menus = $app->getMenu();
|
||||
$menu = $menus->getActive();
|
||||
$title = null;
|
||||
|
||||
// Get the option and view name
|
||||
$option = $this->container->componentName;
|
||||
$view = $this->getName();
|
||||
|
||||
// Get the default page title translation key
|
||||
$default = empty($this->defaultPageTitle) ? $option . '_TITLE_' . $view : $this->defaultPageTitle;
|
||||
|
||||
$params = $app->getParams($option);
|
||||
|
||||
// Set the default value for page_heading
|
||||
if ($menu)
|
||||
{
|
||||
$params->def('page_heading', $params->get('page_title', $menu->title));
|
||||
}
|
||||
else
|
||||
{
|
||||
$params->def('page_heading', Text::_($default));
|
||||
}
|
||||
|
||||
// Set the document title
|
||||
$title = $params->get('page_title', '');
|
||||
$sitename = $app->get('sitename');
|
||||
|
||||
if ($title == $sitename)
|
||||
{
|
||||
$title = Text::_($default);
|
||||
}
|
||||
|
||||
if (empty($title))
|
||||
{
|
||||
$title = $sitename;
|
||||
}
|
||||
elseif ($app->get('sitename_pagetitles', 0) == 1)
|
||||
{
|
||||
$title = Text::sprintf('JPAGETITLE', $app->get('sitename'), $title);
|
||||
}
|
||||
elseif ($app->get('sitename_pagetitles', 0) == 2)
|
||||
{
|
||||
$title = Text::sprintf('JPAGETITLE', $title, $app->get('sitename'));
|
||||
}
|
||||
|
||||
$document->setTitle($title);
|
||||
|
||||
// Set meta
|
||||
if ($params->get('menu-meta_description'))
|
||||
{
|
||||
$document->setDescription($params->get('menu-meta_description'));
|
||||
}
|
||||
|
||||
if ($params->get('menu-meta_keywords'))
|
||||
{
|
||||
$document->setMetadata('keywords', $params->get('menu-meta_keywords'));
|
||||
}
|
||||
|
||||
if ($params->get('robots'))
|
||||
{
|
||||
$document->setMetadata('robots', $params->get('robots'));
|
||||
}
|
||||
|
||||
return $title;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs before rendering the view template, echoing HTML to put before the
|
||||
* view template's generated HTML
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function preRender()
|
||||
{
|
||||
$view = $this->getName();
|
||||
$task = $this->task;
|
||||
|
||||
// Don't load the toolbar on CLI
|
||||
$platform = $this->container->platform;
|
||||
|
||||
if (!$platform->isCli())
|
||||
{
|
||||
$toolbar = $this->container->toolbar;
|
||||
$toolbar->perms = $this->permissions;
|
||||
$toolbar->renderToolbar($view, $task);
|
||||
}
|
||||
|
||||
if ($platform->isFrontend() && $this->setFrontendPageTitle)
|
||||
{
|
||||
$this->setPageTitle();
|
||||
}
|
||||
|
||||
$renderer = $this->container->renderer;
|
||||
$renderer->preRender($view, $task);
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs after rendering the view template, echoing HTML to put after the
|
||||
* view template's generated HTML
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function postRender()
|
||||
{
|
||||
$view = $this->getName();
|
||||
$task = $this->task;
|
||||
|
||||
$renderer = $this->container->renderer;
|
||||
|
||||
if ($renderer instanceof RenderInterface)
|
||||
{
|
||||
$renderer->postRender($view, $task);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes before rendering the page for the Add task.
|
||||
*/
|
||||
protected function onBeforeAdd()
|
||||
{
|
||||
// Hide main menu
|
||||
Factory::getApplication()->input->set('hidemainmenu', true);
|
||||
|
||||
parent::onBeforeAdd();
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes before rendering the page for the Edit task.
|
||||
*/
|
||||
protected function onBeforeEdit()
|
||||
{
|
||||
// Hide main menu
|
||||
Factory::getApplication()->input->set('hidemainmenu', true);
|
||||
|
||||
parent::onBeforeEdit();
|
||||
}
|
||||
}
|
||||
271
libraries/fof30/View/DataView/Json.php
Normal file
271
libraries/fof30/View/DataView/Json.php
Normal file
@ -0,0 +1,271 @@
|
||||
<?php
|
||||
/**
|
||||
* @package FOF
|
||||
* @copyright Copyright (c)2010-2021 Nicholas K. Dionysopoulos / Akeeba Ltd
|
||||
* @license GNU General Public License version 2, or later
|
||||
*/
|
||||
|
||||
namespace FOF30\View\DataView;
|
||||
|
||||
defined('_JEXEC') || die;
|
||||
|
||||
use Exception;
|
||||
use FOF30\Model\DataModel;
|
||||
use Joomla\CMS\Document\Document;
|
||||
use Joomla\CMS\Document\JsonDocument as JDocumentJSON;
|
||||
|
||||
class Json extends Raw implements DataViewInterface
|
||||
{
|
||||
/**
|
||||
* Set to true if your onBefore* methods have already populated the item, items, limitstart etc properties used to
|
||||
* render a JSON document.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $alreadyLoaded = false;
|
||||
|
||||
/**
|
||||
* Record listing offset (how many records to skip before starting showing some)
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $limitStart = 0;
|
||||
|
||||
/**
|
||||
* Record listing limit (how many records to show)
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $limit = 10;
|
||||
|
||||
/**
|
||||
* Total number of records in the result set
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $total = 0;
|
||||
|
||||
/**
|
||||
* The record being displayed
|
||||
*
|
||||
* @var DataModel
|
||||
*/
|
||||
protected $item = null;
|
||||
|
||||
/**
|
||||
* Overrides the default method to execute and display a template script.
|
||||
* Instead of loadTemplate is uses loadAnyTemplate.
|
||||
*
|
||||
* @param string $tpl The name of the template file to parse
|
||||
*
|
||||
* @return boolean True on success
|
||||
*
|
||||
* @throws Exception When the layout file is not found
|
||||
*/
|
||||
public function display($tpl = null)
|
||||
{
|
||||
$eventName = 'onBefore' . ucfirst($this->doTask);
|
||||
$this->triggerEvent($eventName, [$tpl]);
|
||||
|
||||
$eventName = 'onAfter' . ucfirst($this->doTask);
|
||||
$this->triggerEvent($eventName, [$tpl]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* The event which runs when we are displaying the record list JSON view
|
||||
*
|
||||
* @param string $tpl The sub-template to use
|
||||
*/
|
||||
public function onBeforeBrowse($tpl = null)
|
||||
{
|
||||
// Load the model
|
||||
/** @var DataModel $model */
|
||||
$model = $this->getModel();
|
||||
|
||||
$result = '';
|
||||
|
||||
if (!$this->alreadyLoaded)
|
||||
{
|
||||
$this->limitStart = $model->getState('limitstart', 0);
|
||||
$this->limit = $model->getState('limit', 0);
|
||||
$this->items = $model->get(true, $this->limitStart, $this->limit);
|
||||
$this->total = $model->count();
|
||||
}
|
||||
|
||||
$document = $this->container->platform->getDocument();
|
||||
|
||||
/** @var JDocumentJSON $document */
|
||||
if ($document instanceof Document)
|
||||
{
|
||||
$document->setMimeEncoding('application/json');
|
||||
}
|
||||
|
||||
if (is_null($tpl))
|
||||
{
|
||||
$tpl = 'json';
|
||||
}
|
||||
|
||||
$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!
|
||||
$result = [];
|
||||
|
||||
foreach ($this->items as $item)
|
||||
{
|
||||
if (is_object($item) && method_exists($item, 'toArray'))
|
||||
{
|
||||
$result[] = $item->toArray();
|
||||
}
|
||||
else
|
||||
{
|
||||
$result[] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
$json = json_encode($result, JSON_PRETTY_PRINT);
|
||||
|
||||
// JSONP support
|
||||
$callback = $this->input->get('callback', null, 'raw');
|
||||
|
||||
if (!empty($callback))
|
||||
{
|
||||
echo $callback . '(' . $json . ')';
|
||||
}
|
||||
else
|
||||
{
|
||||
$defaultName = $this->input->get('view', 'main', 'cmd');
|
||||
$filename = $this->input->get('basename', $defaultName, 'cmd');
|
||||
|
||||
$document->setName($filename);
|
||||
echo $json;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
echo $result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The event which runs when we are displaying a single item JSON view
|
||||
*
|
||||
* @param string $tpl The view sub-template to use
|
||||
*/
|
||||
protected function onBeforeRead($tpl = null)
|
||||
{
|
||||
self::renderSingleItem($tpl);
|
||||
}
|
||||
|
||||
/**
|
||||
* The event which runs when we are displaying a single item JSON view
|
||||
*
|
||||
* @param string $tpl The view sub-template to use
|
||||
*/
|
||||
protected function onAfterSave($tpl = null)
|
||||
{
|
||||
self::renderSingleItem($tpl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a single item JSON view
|
||||
*
|
||||
* @param string $tpl The view sub-template to use
|
||||
*/
|
||||
protected function renderSingleItem($tpl)
|
||||
{
|
||||
// Load the model
|
||||
/** @var DataModel $model */
|
||||
$model = $this->getModel();
|
||||
|
||||
$result = '';
|
||||
|
||||
if (!$this->alreadyLoaded)
|
||||
{
|
||||
$this->item = $model->find();
|
||||
}
|
||||
|
||||
|
||||
$document = $this->container->platform->getDocument();
|
||||
|
||||
/** @var JDocumentJSON $document */
|
||||
if ($document instanceof Document)
|
||||
{
|
||||
$document->setMimeEncoding('application/json');
|
||||
}
|
||||
|
||||
if (is_null($tpl))
|
||||
{
|
||||
$tpl = 'json';
|
||||
}
|
||||
|
||||
$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 (is_object($this->item) && method_exists($this->item, 'toArray'))
|
||||
{
|
||||
$data = $this->item->toArray();
|
||||
}
|
||||
else
|
||||
{
|
||||
$data = $this->item;
|
||||
}
|
||||
|
||||
$json = json_encode($data, JSON_PRETTY_PRINT);
|
||||
|
||||
// JSONP support
|
||||
$callback = $this->input->get('callback', null);
|
||||
|
||||
if (!empty($callback))
|
||||
{
|
||||
echo $callback . '(' . $json . ')';
|
||||
}
|
||||
else
|
||||
{
|
||||
$defaultName = $this->input->get('view', 'main', 'cmd');
|
||||
$filename = $this->input->get('basename', $defaultName, 'cmd');
|
||||
$document->setName($filename);
|
||||
|
||||
echo $json;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
echo $result;
|
||||
}
|
||||
}
|
||||
}
|
||||
379
libraries/fof30/View/DataView/Raw.php
Normal file
379
libraries/fof30/View/DataView/Raw.php
Normal file
@ -0,0 +1,379 @@
|
||||
<?php
|
||||
/**
|
||||
* @package FOF
|
||||
* @copyright Copyright (c)2010-2021 Nicholas K. Dionysopoulos / Akeeba Ltd
|
||||
* @license GNU General Public License version 2, or later
|
||||
*/
|
||||
|
||||
namespace FOF30\View\DataView;
|
||||
|
||||
defined('_JEXEC') || die;
|
||||
|
||||
use Exception;
|
||||
use FOF30\Container\Container;
|
||||
use FOF30\Model\DataModel;
|
||||
use FOF30\Model\DataModel\Collection;
|
||||
use FOF30\View\View;
|
||||
use Joomla\CMS\Application\SiteApplication;
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\HTML\HTMLHelper;
|
||||
use Joomla\CMS\Pagination\Pagination;
|
||||
use Joomla\Registry\Registry;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* View for a raw data-driven view
|
||||
*/
|
||||
class Raw extends View implements DataViewInterface
|
||||
{
|
||||
/** @var stdClass Data lists */
|
||||
protected $lists = null;
|
||||
|
||||
/** @var Pagination The pagination object */
|
||||
protected $pagination = null;
|
||||
|
||||
/** @var Registry|Registry Page parameters object, for front-end views */
|
||||
protected $pageParams = null;
|
||||
|
||||
/** @var Collection The records loaded (browse views) */
|
||||
protected $items = null;
|
||||
|
||||
/** @var DataModel The record loaded (read, edit, add views) */
|
||||
protected $item = null;
|
||||
|
||||
/** @var int The total number of items in the model (more than those loaded) */
|
||||
protected $itemCount = 0;
|
||||
|
||||
/** @var stdClass ACL permissions map */
|
||||
protected $permissions = null;
|
||||
|
||||
/** @var array Additional permissions to fetch on object creation, see getPermissions() */
|
||||
protected $additionalPermissions = [];
|
||||
|
||||
/**
|
||||
* Overrides the constructor to apply Joomla! ACL permissions
|
||||
*
|
||||
* @param Container $container The container we belong to
|
||||
* @param array $config The configuration overrides for the view
|
||||
*/
|
||||
public function __construct(Container $container, array $config = [])
|
||||
{
|
||||
parent::__construct($container, $config);
|
||||
|
||||
$this->permissions = $this->getPermissions(null, $this->additionalPermissions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the current Joomla! version and your current table support AJAX-powered drag and drop reordering.
|
||||
* If they do, it will set up the drag & drop reordering feature.
|
||||
*
|
||||
* @return boolean|array False if not supported, otherwise a table with necessary information (saveOrder: should
|
||||
* you enable DnD reordering; orderingColumn: which column has the ordering information).
|
||||
*/
|
||||
public function hasAjaxOrderingSupport()
|
||||
{
|
||||
/** @var DataModel $model */
|
||||
$model = $this->getModel();
|
||||
|
||||
if (!$model->hasField('ordering'))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$listOrder = $this->escape($model->getState('filter_order', null, 'cmd'));
|
||||
$listDirn = $this->escape($model->getState('filter_order_Dir', null, 'cmd'));
|
||||
$saveOrder = $listOrder == $model->getFieldAlias('ordering');
|
||||
$saveOrderingUrl = '';
|
||||
|
||||
if ($saveOrder)
|
||||
{
|
||||
$saveOrderingUrl = 'index.php?option=' . $this->container->componentName . '&view=' . $this->getName() . '&task=saveorder&format=json';
|
||||
$helper = version_compare(JVERSION, '3.999.999', 'le') ? 'sortablelist.sortable' : 'draggablelist.draggable';
|
||||
|
||||
HtmlHelper::_($helper, 'itemsList', 'adminForm', strtolower($listDirn), $saveOrderingUrl);
|
||||
}
|
||||
|
||||
return [
|
||||
'saveOrder' => $saveOrder,
|
||||
'saveOrderURL' => $saveOrderingUrl . '&' . $this->container->platform->getToken() . '=1',
|
||||
'orderingColumn' => $model->getFieldAlias('ordering'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the internal list of useful variables to the benefit of header fields.
|
||||
*
|
||||
* @return stdClass
|
||||
*/
|
||||
public function getLists()
|
||||
{
|
||||
return $this->lists;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the permissions object of this view
|
||||
*
|
||||
* @return stdClass
|
||||
*/
|
||||
public function getPerms()
|
||||
{
|
||||
return $this->permissions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the pagination object of this view
|
||||
*
|
||||
* @return Pagination
|
||||
*/
|
||||
public function getPagination()
|
||||
{
|
||||
return $this->pagination;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the items collection for browse views
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getItems()
|
||||
{
|
||||
return $this->items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the item for read, edit, add views
|
||||
*
|
||||
* @return DataModel
|
||||
*/
|
||||
public function getItem()
|
||||
{
|
||||
return $this->item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the items count for browse views
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getItemCount()
|
||||
{
|
||||
return $this->itemCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Joomla! page parameters
|
||||
*
|
||||
* @return Registry|Registry
|
||||
*/
|
||||
public function getPageParams()
|
||||
{
|
||||
return $this->pageParams;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a permissions object.
|
||||
*
|
||||
* The additionalPermissions array is a hashed array of local key => Joomla! ACL key value pairs. Local key is the
|
||||
* name of the permission in the permissions object, whereas Joomla! ACL key is the name of the ACL permission
|
||||
* known to Joomla! e.g. "core.manage", "foobar.something" and so on.
|
||||
*
|
||||
* Note: on CLI applications all permissions are set to TRUE. There is no ACL check there.
|
||||
*
|
||||
* @param null|string $component The name of the component. Leave empty for automatic detection.
|
||||
* @param array $additionalPermissions Any additional permissions you want to add to the object.
|
||||
*
|
||||
* @return object
|
||||
*/
|
||||
protected function getPermissions($component = null, array $additionalPermissions = [])
|
||||
{
|
||||
// Make sure we have a component
|
||||
if (empty($component))
|
||||
{
|
||||
$component = $this->container->componentName;
|
||||
}
|
||||
|
||||
// Initialise with all true
|
||||
$permissions = [
|
||||
'create' => true,
|
||||
'edit' => true,
|
||||
'editown' => true,
|
||||
'editstate' => true,
|
||||
'delete' => true,
|
||||
];
|
||||
|
||||
if (!empty($additionalPermissions))
|
||||
{
|
||||
foreach ($additionalPermissions as $localKey => $joomlaPermission)
|
||||
{
|
||||
$permissions[$localKey] = true;
|
||||
}
|
||||
}
|
||||
|
||||
$platform = $this->container->platform;
|
||||
|
||||
// If this is a CLI application we don't make any ACL checks
|
||||
if ($platform->isCli())
|
||||
{
|
||||
return (object) $permissions;
|
||||
}
|
||||
|
||||
// Get the core permissions
|
||||
$permissions = [
|
||||
'create' => $platform->authorise('core.create', $component),
|
||||
'edit' => $platform->authorise('core.edit', $component),
|
||||
'editown' => $platform->authorise('core.edit.own', $component),
|
||||
'editstate' => $platform->authorise('core.edit.state', $component),
|
||||
'delete' => $platform->authorise('core.delete', $component),
|
||||
];
|
||||
|
||||
if (!empty($additionalPermissions))
|
||||
{
|
||||
foreach ($additionalPermissions as $localKey => $joomlaPermission)
|
||||
{
|
||||
$permissions[$localKey] = $platform->authorise($joomlaPermission, $component);
|
||||
}
|
||||
}
|
||||
|
||||
return (object) $permissions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes before rendering the page for the Browse task.
|
||||
*/
|
||||
protected function onBeforeBrowse()
|
||||
{
|
||||
// Create the lists object
|
||||
$this->lists = new stdClass();
|
||||
|
||||
// Load the model
|
||||
/** @var DataModel $model */
|
||||
$model = $this->getModel();
|
||||
|
||||
// We want to persist the state in the session
|
||||
$model->savestate(1);
|
||||
|
||||
// Display limits
|
||||
$defaultLimit = 20;
|
||||
|
||||
if (!$this->container->platform->isCli() && class_exists('JFactory'))
|
||||
{
|
||||
$app = Factory::getApplication();
|
||||
|
||||
if (method_exists($app, 'get'))
|
||||
{
|
||||
$defaultLimit = $app->get('list_limit');
|
||||
}
|
||||
else
|
||||
{
|
||||
$defaultLimit = 20;
|
||||
}
|
||||
}
|
||||
|
||||
$this->lists->limitStart = $model->getState('limitstart', 0, 'int');
|
||||
$this->lists->limit = $model->getState('limit', $defaultLimit, 'int');
|
||||
|
||||
$model->limitstart = $this->lists->limitStart;
|
||||
$model->limit = $this->lists->limit;
|
||||
|
||||
// Assign items to the view
|
||||
$this->items = $model->get(false);
|
||||
$this->itemCount = $model->count();
|
||||
|
||||
// Ordering information
|
||||
$this->lists->order = $model->getState('filter_order', $model->getIdFieldName(), 'cmd');
|
||||
$this->lists->order_Dir = $model->getState('filter_order_Dir', null, 'cmd');
|
||||
|
||||
if ($this->lists->order_Dir)
|
||||
{
|
||||
$this->lists->order_Dir = strtolower($this->lists->order_Dir);
|
||||
}
|
||||
|
||||
// Pagination
|
||||
$this->pagination = new Pagination($this->itemCount, $this->lists->limitStart, $this->lists->limit);
|
||||
|
||||
// Pass page params on frontend only
|
||||
if ($this->container->platform->isFrontend())
|
||||
{
|
||||
/** @var SiteApplication $app */
|
||||
$app = Factory::getApplication();
|
||||
$params = $app->getParams();
|
||||
$this->pageParams = $params;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes before rendering the page for the add task.
|
||||
*/
|
||||
protected function onBeforeAdd()
|
||||
{
|
||||
/** @var DataModel $model */
|
||||
$model = $this->getModel();
|
||||
|
||||
/**
|
||||
* The model is pushed into the View by the Controller. As you can see in DataController::add() it is possible
|
||||
* to push both default values (defaultsForAdd) as well as data from the state (e.g. when saving a new record
|
||||
* failed for some reason and the user needs to edit it). That's why we populate defaultFields from $model. We
|
||||
* still do a full reset on a clone of the Model to get a clean object and merge default values (instead of null
|
||||
* values) with the data pushed by the controller.
|
||||
*/
|
||||
$defaultFields = $model->getData();
|
||||
$this->item = $model->getClone()->reset(true, true);
|
||||
|
||||
foreach ($defaultFields as $k => $v)
|
||||
{
|
||||
try
|
||||
{
|
||||
$this->item->setFieldValue($k, $v);
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
// Suppress errors in field assignments at this stage
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes before rendering the page for the Edit task.
|
||||
*/
|
||||
protected function onBeforeEdit()
|
||||
{
|
||||
/** @var DataModel $model */
|
||||
$model = $this->getModel();
|
||||
|
||||
// It seems that I can't edit records, maybe I can edit only this one due asset tracking?
|
||||
if (!$this->permissions->edit || !$this->permissions->editown)
|
||||
{
|
||||
if ($model)
|
||||
{
|
||||
// Ok, record is tracked, let's see if I can this record
|
||||
if ($model->isAssetsTracked())
|
||||
{
|
||||
$platform = $this->container->platform;
|
||||
|
||||
if (!$this->permissions->edit)
|
||||
{
|
||||
$this->permissions->edit = $platform->authorise('core.edit', $model->getAssetName());
|
||||
}
|
||||
|
||||
if (!$this->permissions->editown)
|
||||
{
|
||||
$this->permissions->editown = $platform->authorise('core.edit.own', $model->getAssetName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->item = $model->findOrFail();
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes before rendering the page for the Read task.
|
||||
*/
|
||||
protected function onBeforeRead()
|
||||
{
|
||||
/** @var DataModel $model */
|
||||
$model = $this->getModel();
|
||||
|
||||
$this->item = $model->findOrFail();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user