primo commit
This commit is contained in:
1230
libraries/fof30/View/Compiler/Blade.php
Normal file
1230
libraries/fof30/View/Compiler/Blade.php
Normal file
File diff suppressed because it is too large
Load Diff
40
libraries/fof30/View/Compiler/CompilerInterface.php
Normal file
40
libraries/fof30/View/Compiler/CompilerInterface.php
Normal file
@ -0,0 +1,40 @@
|
||||
<?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\Compiler;
|
||||
|
||||
defined('_JEXEC') || die;
|
||||
|
||||
interface CompilerInterface
|
||||
{
|
||||
/**
|
||||
* Are the results of this compiler engine cacheable? If the engine makes use of the forcedParams it must return
|
||||
* false.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function isCacheable();
|
||||
|
||||
/**
|
||||
* Compile a view template into PHP and HTML
|
||||
*
|
||||
* @param string $path The absolute filesystem path of the view template
|
||||
* @param array $forceParams Any parameters to force (only for engines returning raw HTML)
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function compile($path, array $forceParams = []);
|
||||
|
||||
/**
|
||||
* Returns the file extension supported by this compiler
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @since 3.3.1
|
||||
*/
|
||||
public function getFileExtension();
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
||||
45
libraries/fof30/View/Engine/AbstractEngine.php
Normal file
45
libraries/fof30/View/Engine/AbstractEngine.php
Normal file
@ -0,0 +1,45 @@
|
||||
<?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\Engine;
|
||||
|
||||
defined('_JEXEC') || die;
|
||||
|
||||
use FOF30\View\View;
|
||||
|
||||
abstract class AbstractEngine implements EngineInterface
|
||||
{
|
||||
/** @var View The view we belong to */
|
||||
protected $view = null;
|
||||
|
||||
/**
|
||||
* Public constructor
|
||||
*
|
||||
* @param View $view The view we belong to
|
||||
*/
|
||||
public function __construct(View $view)
|
||||
{
|
||||
$this->view = $view;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the include path for a parsed view template
|
||||
*
|
||||
* @param string $path The path to the view template
|
||||
* @param array $forceParams Any additional information to pass to the view template engine
|
||||
*
|
||||
* @return array Content 3ναlυα+ιοη information (I use leetspeak here because of bad quality hosts with broken
|
||||
* scanners)
|
||||
*/
|
||||
public function get($path, array $forceParams = [])
|
||||
{
|
||||
return [
|
||||
'type' => 'raw',
|
||||
'content' => '',
|
||||
];
|
||||
}
|
||||
}
|
||||
26
libraries/fof30/View/Engine/BladeEngine.php
Normal file
26
libraries/fof30/View/Engine/BladeEngine.php
Normal file
@ -0,0 +1,26 @@
|
||||
<?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\Engine;
|
||||
|
||||
defined('_JEXEC') || die;
|
||||
|
||||
use FOF30\View\View;
|
||||
|
||||
/**
|
||||
* View engine for compiling PHP template files.
|
||||
*/
|
||||
class BladeEngine extends CompilingEngine implements EngineInterface
|
||||
{
|
||||
public function __construct(View $view)
|
||||
{
|
||||
parent::__construct($view);
|
||||
|
||||
// Assign the Blade compiler to this engine
|
||||
$this->compiler = $view->getContainer()->blade;
|
||||
}
|
||||
}
|
||||
273
libraries/fof30/View/Engine/CompilingEngine.php
Normal file
273
libraries/fof30/View/Engine/CompilingEngine.php
Normal file
@ -0,0 +1,273 @@
|
||||
<?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\Engine;
|
||||
|
||||
defined('_JEXEC') || die;
|
||||
|
||||
use FOF30\Utils\Buffer;
|
||||
use FOF30\View\Compiler\CompilerInterface;
|
||||
use FOF30\View\Exception\PossiblySuhosin;
|
||||
use JLoader;
|
||||
use Joomla\CMS\Filesystem\File;
|
||||
|
||||
/**
|
||||
* View engine for compiling PHP template files.
|
||||
*/
|
||||
abstract class CompilingEngine extends AbstractEngine implements EngineInterface
|
||||
{
|
||||
/** @var CompilerInterface The compiler used by this engine */
|
||||
protected $compiler = null;
|
||||
|
||||
/**
|
||||
* Get the 3ναlυa+3d contents of the view template. (I use leetspeak here because of bad quality hosts with broken
|
||||
* scanners)
|
||||
*
|
||||
* @param string $path The path to the view template
|
||||
* @param array $forceParams Any additional information to pass to the view template engine
|
||||
*
|
||||
* @return array Content evaluation information
|
||||
*/
|
||||
public function get($path, array $forceParams = [])
|
||||
{
|
||||
// If it's cached return the path to the cached file's path
|
||||
if ($this->isCached($path))
|
||||
{
|
||||
return [
|
||||
'type' => 'path',
|
||||
'content' => $this->getCachePath($path),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile and cache the file. We also add the file path in a comment at the top of the file so phpStorm can
|
||||
* debug it.
|
||||
*
|
||||
* @see https://blog.jetbrains.com/phpstorm/2019/02/phpstorm-2019-1-eap-191-5849-26/
|
||||
* @see https://laravel-news.com/laravel-5-8-blade-template-file-path
|
||||
*/
|
||||
$content = "<?php /* $path */ ?>\n";
|
||||
$content .= $this->compile($path, $forceParams);
|
||||
$cachePath = $this->putToCache($path, $content);
|
||||
$isPHPFile = substr($path, -4) == '.php';
|
||||
|
||||
// If we could cache it, return the cached file's path
|
||||
if ($cachePath !== false)
|
||||
{
|
||||
// Bust the opcode cache for .php files
|
||||
if ($isPHPFile)
|
||||
{
|
||||
$this->bustOpCache($path);
|
||||
}
|
||||
|
||||
return [
|
||||
'type' => 'path',
|
||||
'content' => $cachePath,
|
||||
];
|
||||
}
|
||||
|
||||
// We could not write to the cache. Hm, can I use a stream wrapper?
|
||||
$canUseStreams = Buffer::canRegisterWrapper();
|
||||
|
||||
if ($canUseStreams)
|
||||
{
|
||||
$id = $this->getIdentifier($path);
|
||||
$streamPath = 'fof://' . $this->view->getContainer()->componentName . '/compiled_templates/' . $id . '.php';
|
||||
file_put_contents($streamPath, $content);
|
||||
|
||||
// Bust the opcode cache for .php files
|
||||
if ($isPHPFile)
|
||||
{
|
||||
$this->bustOpCache($path);
|
||||
}
|
||||
|
||||
return [
|
||||
'type' => 'path',
|
||||
'content' => $streamPath,
|
||||
];
|
||||
}
|
||||
|
||||
// I couldn't use a stream wrapper. I have to give up.
|
||||
throw new PossiblySuhosin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the path where I can find a precompiled version of the unprocessed view template which lives in $path
|
||||
*
|
||||
* @param string $path The path to the uncompiled view template
|
||||
*
|
||||
* @return bool|string False if the view template is outside the component's front- or backend.
|
||||
*
|
||||
* @since 3.3.1
|
||||
*/
|
||||
public function getPrecompiledPath($path)
|
||||
{
|
||||
// Normalize the path to the file
|
||||
$path = realpath($path);
|
||||
|
||||
if ($path === false)
|
||||
{
|
||||
// The file doesn't exist
|
||||
return false;
|
||||
}
|
||||
|
||||
// Is this path under the component's front- or backend?
|
||||
$frontendPath = realpath($this->view->getContainer()->frontEndPath);
|
||||
$backendPath = realpath($this->view->getContainer()->backEndPath);
|
||||
|
||||
$backPos = strpos($path, $backendPath);
|
||||
$frontPos = strpos($path, $frontendPath);
|
||||
|
||||
if (($backPos !== 0) && ($frontPos !== 0))
|
||||
{
|
||||
// This is not a view template shipped with the component, i.e. it can't be precompiled
|
||||
return false;
|
||||
}
|
||||
|
||||
// Eliminate the component path from $path to get the relative path to the file
|
||||
$componentPath = $frontendPath;
|
||||
|
||||
if ($backPos === 0)
|
||||
{
|
||||
$componentPath = $backendPath;
|
||||
}
|
||||
|
||||
$relativePath = ltrim(substr($path, strlen($componentPath)), '\\/');
|
||||
|
||||
// Break down the relative path to its parts
|
||||
$relativePath = str_replace('\\', '/', $relativePath);
|
||||
$pathParts = explode('/', $relativePath);
|
||||
|
||||
// Remove the prefix
|
||||
$prefix = array_shift($pathParts);
|
||||
|
||||
// If it's a legacy view, View, Views, or views prefix remove the 'tmpl' part
|
||||
if ($prefix != 'ViewTemplates')
|
||||
{
|
||||
unset($pathParts[1]);
|
||||
}
|
||||
|
||||
// Get the last part and process the extension
|
||||
$viewFile = array_pop($pathParts);
|
||||
$extensionWithoutDot = $this->compiler->getFileExtension();
|
||||
$pathParts[] = substr($viewFile, 0, -strlen($extensionWithoutDot)) . 'php';
|
||||
|
||||
$precompiledRelativePath = implode(DIRECTORY_SEPARATOR, $pathParts);
|
||||
|
||||
return $componentPath . DIRECTORY_SEPARATOR . 'PrecompiledTemplates' . DIRECTORY_SEPARATOR . $precompiledRelativePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* A method to compile the raw view template into valid PHP
|
||||
*
|
||||
* @param string $path The path to the view template
|
||||
* @param array $forceParams Any additional information to pass to the view template compiler
|
||||
*
|
||||
* @return string The template compiled to executable PHP
|
||||
*/
|
||||
protected function compile($path, array $forceParams = [])
|
||||
{
|
||||
return $this->compiler->compile($path, $forceParams);
|
||||
}
|
||||
|
||||
protected function getIdentifier($path)
|
||||
{
|
||||
if (function_exists('sha1'))
|
||||
{
|
||||
return sha1($path);
|
||||
}
|
||||
|
||||
return md5($path);
|
||||
}
|
||||
|
||||
protected function getCachePath($path)
|
||||
{
|
||||
$id = $this->getIdentifier($path);
|
||||
|
||||
return JPATH_CACHE . '/' . $this->view->getContainer()->componentName . '/compiled_templates/' . $id . '.php';
|
||||
}
|
||||
|
||||
protected function isCached($path)
|
||||
{
|
||||
if (!$this->compiler->isCacheable())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$cachePath = $this->getCachePath($path);
|
||||
|
||||
if (!file_exists($cachePath))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$cacheTime = filemtime($cachePath);
|
||||
$fileTime = filemtime($path);
|
||||
|
||||
return $fileTime <= $cacheTime;
|
||||
}
|
||||
|
||||
protected function getCached($path)
|
||||
{
|
||||
$cachePath = $this->getCachePath($path);
|
||||
|
||||
return file_get_contents($cachePath);
|
||||
}
|
||||
|
||||
protected function putToCache($path, $content)
|
||||
{
|
||||
$cachePath = $this->getCachePath($path);
|
||||
|
||||
if (@file_put_contents($cachePath, $content))
|
||||
{
|
||||
return $cachePath;
|
||||
}
|
||||
|
||||
if (File::write($cachePath, $content))
|
||||
{
|
||||
return $cachePath;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bust the opcode cache for a given .php file
|
||||
*
|
||||
* This method can address opcode caching with:
|
||||
* - Zend OPcache
|
||||
* - Alternative PHP Cache (now defunct)
|
||||
* - Windows Cache Extension for PHP (versions lower than 2.0.0)
|
||||
* - XCache (now defunct)
|
||||
*
|
||||
* @param string $path The file to bus the cache for
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function bustOpCache($path)
|
||||
{
|
||||
if (function_exists('opcache_invalidate'))
|
||||
{
|
||||
opcache_invalidate($path);
|
||||
}
|
||||
|
||||
if (function_exists('apc_compile_file'))
|
||||
{
|
||||
apc_compile_file($path);
|
||||
}
|
||||
|
||||
if (function_exists('wincache_refresh_if_changed'))
|
||||
{
|
||||
wincache_refresh_if_changed([$path]);
|
||||
}
|
||||
|
||||
if (function_exists('xcache_asm'))
|
||||
{
|
||||
xcache_asm($path);
|
||||
}
|
||||
}
|
||||
}
|
||||
33
libraries/fof30/View/Engine/EngineInterface.php
Normal file
33
libraries/fof30/View/Engine/EngineInterface.php
Normal file
@ -0,0 +1,33 @@
|
||||
<?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\Engine;
|
||||
|
||||
defined('_JEXEC') || die;
|
||||
|
||||
use FOF30\View\View;
|
||||
|
||||
interface EngineInterface
|
||||
{
|
||||
/**
|
||||
* Public constructor
|
||||
*
|
||||
* @param View $view The view we belong to
|
||||
*/
|
||||
public function __construct(View $view);
|
||||
|
||||
/**
|
||||
* Get the include path for a parsed view template
|
||||
*
|
||||
* @param string $path The path to the view template
|
||||
* @param array $forceParams Any additional information to pass to the view template engine
|
||||
*
|
||||
* @return array Content 3ναlυα+ιοη information ['type' => 'raw|path', 'content' => 'path or raw content'] (I use
|
||||
* leetspeak here because of bad quality hosts with broken scanners)
|
||||
*/
|
||||
public function get($path, array $forceParams = []);
|
||||
}
|
||||
34
libraries/fof30/View/Engine/PhpEngine.php
Normal file
34
libraries/fof30/View/Engine/PhpEngine.php
Normal file
@ -0,0 +1,34 @@
|
||||
<?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\Engine;
|
||||
|
||||
defined('_JEXEC') || die;
|
||||
|
||||
/**
|
||||
* View engine for plain PHP template files (no translation).
|
||||
*/
|
||||
class PhpEngine extends AbstractEngine implements EngineInterface
|
||||
{
|
||||
/**
|
||||
* Get the 3ναluα+3d contents of the view template. (I use leetspeak here because of bad quality hosts with broken
|
||||
* scanners)
|
||||
*
|
||||
* @param string $path The path to the view template
|
||||
* @param array $forceParams Any additional information to pass to the view template engine
|
||||
*
|
||||
* @return array Content 3ναlυα+ιοη information (I use leetspeak here because of asshole hosts with broken
|
||||
* scanners)
|
||||
*/
|
||||
public function get($path, array $forceParams = [])
|
||||
{
|
||||
return [
|
||||
'type' => 'path',
|
||||
'content' => $path,
|
||||
];
|
||||
}
|
||||
}
|
||||
31
libraries/fof30/View/Exception/AccessForbidden.php
Normal file
31
libraries/fof30/View/Exception/AccessForbidden.php
Normal file
@ -0,0 +1,31 @@
|
||||
<?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\Exception;
|
||||
|
||||
defined('_JEXEC') || die;
|
||||
|
||||
use Exception;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
* Exception thrown when the access to the requested resource is forbidden under the current execution context
|
||||
*/
|
||||
class AccessForbidden extends RuntimeException
|
||||
{
|
||||
public function __construct($message = "", $code = 403, Exception $previous = null)
|
||||
{
|
||||
if (empty($message))
|
||||
{
|
||||
$message = Text::_('JLIB_APPLICATION_ERROR_ACCESS_FORBIDDEN');
|
||||
}
|
||||
|
||||
parent::__construct($message, $code, $previous);
|
||||
}
|
||||
|
||||
}
|
||||
30
libraries/fof30/View/Exception/CannotGetName.php
Normal file
30
libraries/fof30/View/Exception/CannotGetName.php
Normal file
@ -0,0 +1,30 @@
|
||||
<?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\Exception;
|
||||
|
||||
defined('_JEXEC') || die;
|
||||
|
||||
use Exception;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
* Exception thrown when we can't get a Controller's name
|
||||
*/
|
||||
class CannotGetName extends RuntimeException
|
||||
{
|
||||
public function __construct($message = "", $code = 500, Exception $previous = null)
|
||||
{
|
||||
if (empty($message))
|
||||
{
|
||||
$message = Text::_('LIB_FOF_VIEW_ERR_GET_NAME');
|
||||
}
|
||||
|
||||
parent::__construct($message, $code, $previous);
|
||||
}
|
||||
}
|
||||
27
libraries/fof30/View/Exception/EmptyStack.php
Normal file
27
libraries/fof30/View/Exception/EmptyStack.php
Normal file
@ -0,0 +1,27 @@
|
||||
<?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\Exception;
|
||||
|
||||
defined('_JEXEC') || die;
|
||||
|
||||
use Exception;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
* Exception thrown when we are trying to operate on an empty section stack
|
||||
*/
|
||||
class EmptyStack extends RuntimeException
|
||||
{
|
||||
public function __construct($message = "", $code = 500, Exception $previous = null)
|
||||
{
|
||||
$message = Text::_('LIB_FOF_VIEW_EMPTYSECTIONSTACK');
|
||||
|
||||
parent::__construct($message, $code, $previous);
|
||||
}
|
||||
}
|
||||
27
libraries/fof30/View/Exception/ModelNotFound.php
Normal file
27
libraries/fof30/View/Exception/ModelNotFound.php
Normal file
@ -0,0 +1,27 @@
|
||||
<?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\Exception;
|
||||
|
||||
defined('_JEXEC') || die;
|
||||
|
||||
use Exception;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
* Exception thrown when we can't get a Controller's name
|
||||
*/
|
||||
class ModelNotFound extends RuntimeException
|
||||
{
|
||||
public function __construct($path, $viewName, $code = 500, Exception $previous = null)
|
||||
{
|
||||
$message = Text::sprintf('LIB_FOF_VIEW_MODELNOTINVIEW', $path, $viewName);
|
||||
|
||||
parent::__construct($message, $code, $previous);
|
||||
}
|
||||
}
|
||||
31
libraries/fof30/View/Exception/PossiblySuhosin.php
Normal file
31
libraries/fof30/View/Exception/PossiblySuhosin.php
Normal file
@ -0,0 +1,31 @@
|
||||
<?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\Exception;
|
||||
|
||||
defined('_JEXEC') || die;
|
||||
|
||||
use Exception;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
* Exception thrown when the access to the requested resource is forbidden under the current execution context
|
||||
*/
|
||||
class PossiblySuhosin extends RuntimeException
|
||||
{
|
||||
public function __construct($message = "", $code = 403, Exception $previous = null)
|
||||
{
|
||||
if (empty($message))
|
||||
{
|
||||
$message = Text::_('LIB_FOF_VIEW_POSSIBLYSUHOSIN');
|
||||
}
|
||||
|
||||
parent::__construct($message, $code, $previous);
|
||||
}
|
||||
|
||||
}
|
||||
27
libraries/fof30/View/Exception/UnrecognisedExtension.php
Normal file
27
libraries/fof30/View/Exception/UnrecognisedExtension.php
Normal file
@ -0,0 +1,27 @@
|
||||
<?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\Exception;
|
||||
|
||||
defined('_JEXEC') || die;
|
||||
|
||||
use Exception;
|
||||
use InvalidArgumentException;
|
||||
use Joomla\CMS\Language\Text;
|
||||
|
||||
/**
|
||||
* Exception thrown when we can't figure out which engine to use for a view template
|
||||
*/
|
||||
class UnrecognisedExtension extends InvalidArgumentException
|
||||
{
|
||||
public function __construct($path, $code = 500, Exception $previous = null)
|
||||
{
|
||||
$message = Text::sprintf('LIB_FOF_VIEW_UNRECOGNISEDEXTENSION', $path);
|
||||
|
||||
parent::__construct($message, $code, $previous);
|
||||
}
|
||||
}
|
||||
1433
libraries/fof30/View/View.php
Normal file
1433
libraries/fof30/View/View.php
Normal file
File diff suppressed because it is too large
Load Diff
603
libraries/fof30/View/ViewTemplateFinder.php
Normal file
603
libraries/fof30/View/ViewTemplateFinder.php
Normal file
@ -0,0 +1,603 @@
|
||||
<?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;
|
||||
|
||||
defined('_JEXEC') || die;
|
||||
|
||||
use FOF30\Container\Container;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
* Locates the appropriate template file for a view
|
||||
*/
|
||||
class ViewTemplateFinder
|
||||
{
|
||||
/** @var View The view we are attached to */
|
||||
protected $view;
|
||||
|
||||
/** @var Container The container of the view, for quick reference */
|
||||
protected $container;
|
||||
|
||||
/** @var array The layout template extensions to look for */
|
||||
protected $extensions = ['.blade.php', '.php'];
|
||||
|
||||
/** @var string Default layout's name (default: "default") */
|
||||
protected $defaultLayout = 'default';
|
||||
|
||||
/** @var string Default subtemplate name (default: empty) */
|
||||
protected $defaultTpl = '';
|
||||
|
||||
/** @var bool Should I only look in the specified view (true) or also the pluralised/singularised (false) */
|
||||
protected $strictView = true;
|
||||
|
||||
/** @var bool Should I only look for the defined subtemplate or also no subtemplate? */
|
||||
protected $strictTpl = true;
|
||||
|
||||
/** @var bool Should Should I only look for this layout or also the default layout? */
|
||||
protected $strictLayout = true;
|
||||
|
||||
/** @var string Which application side prefix should I use by default (site, admin, auto, any) */
|
||||
protected $sidePrefix = 'auto';
|
||||
|
||||
/**
|
||||
* Public constructor. The config array can contain the following keys
|
||||
* extensions array
|
||||
* defaultLayout string
|
||||
* defaultTpl string
|
||||
* strictView bool
|
||||
* strictTpl bool
|
||||
* strictLayout bool
|
||||
* sidePrefix string
|
||||
* For the descriptions of each key please see the same-named property of this class
|
||||
*
|
||||
* @param View $view The view we are attached to
|
||||
* @param array $config The configuration for this view template finder
|
||||
*/
|
||||
function __construct(View $view, array $config = [])
|
||||
{
|
||||
$this->view = $view;
|
||||
$this->container = $view->getContainer();
|
||||
|
||||
if (isset($config['extensions']))
|
||||
{
|
||||
if (!is_array($config['extensions']))
|
||||
{
|
||||
$config['extensions'] = trim($config['extensions']);
|
||||
$config['extensions'] = explode(',', $config['extensions']);
|
||||
$config['extensions'] = array_map(function ($x) {
|
||||
return trim($x);
|
||||
}, $config['extensions']);
|
||||
}
|
||||
|
||||
$this->setExtensions($config['extensions']);
|
||||
}
|
||||
|
||||
if (isset($config['defaultLayout']))
|
||||
{
|
||||
$this->setDefaultLayout($config['defaultLayout']);
|
||||
}
|
||||
|
||||
if (isset($config['defaultTpl']))
|
||||
{
|
||||
$this->setDefaultTpl($config['defaultTpl']);
|
||||
}
|
||||
|
||||
if (isset($config['strictView']))
|
||||
{
|
||||
$config['strictView'] = in_array($config['strictView'], [true, 'true', 'yes', 'on', 1]);
|
||||
|
||||
$this->setStrictView($config['strictView']);
|
||||
}
|
||||
|
||||
if (isset($config['strictTpl']))
|
||||
{
|
||||
$config['strictTpl'] = in_array($config['strictTpl'], [true, 'true', 'yes', 'on', 1]);
|
||||
|
||||
$this->setStrictTpl($config['strictTpl']);
|
||||
}
|
||||
|
||||
if (isset($config['strictLayout']))
|
||||
{
|
||||
$config['strictLayout'] = in_array($config['strictLayout'], [true, 'true', 'yes', 'on', 1]);
|
||||
|
||||
$this->setStrictLayout($config['strictLayout']);
|
||||
}
|
||||
|
||||
if (isset($config['sidePrefix']))
|
||||
{
|
||||
$this->setSidePrefix($config['sidePrefix']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of template URIs for a specific component, view, template and sub-template. The $parameters array
|
||||
* can have any of the following keys:
|
||||
* component string The name of the component, e.g. com_something
|
||||
* view string The name of the view
|
||||
* layout string The name of the layout
|
||||
* tpl string The name of the subtemplate
|
||||
* strictView bool Should I only look in the specified view, or should I look in the
|
||||
* pluralised/singularised view as well? strictLayout bool Should I only look for this layout, or also for
|
||||
* the default layout? strictTpl bool Should I only look for this subtemplate or also for no subtemplate?
|
||||
* sidePrefix string The application side prefix (site, admin, auto, any)
|
||||
*
|
||||
* @param array $parameters See above
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getViewTemplateUris(array $parameters)
|
||||
{
|
||||
// Merge the default parameters with the parameters given
|
||||
$parameters = array_merge([
|
||||
'component' => $this->container->componentName,
|
||||
'view' => $this->view->getName(),
|
||||
'layout' => $this->defaultLayout,
|
||||
'tpl' => $this->defaultTpl,
|
||||
'strictView' => $this->strictView,
|
||||
'strictLayout' => $this->strictLayout,
|
||||
'strictTpl' => $this->strictTpl,
|
||||
'sidePrefix' => $this->sidePrefix,
|
||||
], $parameters);
|
||||
|
||||
$uris = [];
|
||||
|
||||
$component = $parameters['component'];
|
||||
$view = $parameters['view'];
|
||||
$layout = $parameters['layout'];
|
||||
$tpl = $parameters['tpl'];
|
||||
$strictView = $parameters['strictView'];
|
||||
$strictLayout = $parameters['strictLayout'];
|
||||
$strictTpl = $parameters['strictTpl'];
|
||||
$sidePrefix = $parameters['sidePrefix'];
|
||||
|
||||
$basePath = $sidePrefix . ':' . $component . '/' . $view . '/';
|
||||
|
||||
$uris[] = $basePath . $layout . ($tpl ? "_$tpl" : '');
|
||||
|
||||
if (!$strictTpl)
|
||||
{
|
||||
$uris[] = $basePath . $layout;
|
||||
}
|
||||
|
||||
if (!$strictLayout)
|
||||
{
|
||||
$uris[] = $basePath . 'default' . ($tpl ? "_$tpl" : '');
|
||||
|
||||
if (!$strictTpl)
|
||||
{
|
||||
$uris[] = $basePath . 'default';
|
||||
}
|
||||
}
|
||||
|
||||
if (!$strictView)
|
||||
{
|
||||
$parameters['view'] = $this->container->inflector->isSingular($view) ? $this->container->inflector->pluralize($view) : $this->container->inflector->singularize($view);
|
||||
$parameters['strictView'] = true;
|
||||
|
||||
$extraUris = $this->getViewTemplateUris($parameters);
|
||||
$uris = array_merge($uris, $extraUris);
|
||||
unset ($extraUris);
|
||||
}
|
||||
|
||||
return array_unique($uris);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a template URI in the form of admin:component/view/layout to an array listing the application section
|
||||
* (admin, site), component, view and template referenced therein.
|
||||
*
|
||||
* @param string $uri The template path to parse
|
||||
*
|
||||
* @return array A hash array with the parsed path parts. Keys: admin, component, view, template
|
||||
*/
|
||||
public function parseTemplateUri($uri = '')
|
||||
{
|
||||
$parts = [
|
||||
'admin' => 0,
|
||||
'component' => $this->container->componentName,
|
||||
'view' => $this->view->getName(),
|
||||
'template' => 'default',
|
||||
];
|
||||
|
||||
if (substr($uri, 0, 5) == 'auto:')
|
||||
{
|
||||
$replacement = $this->container->platform->isBackend() ? 'admin:' : 'site:';
|
||||
$uri = $replacement . substr($uri, 5);
|
||||
}
|
||||
|
||||
if (substr($uri, 0, 6) == 'admin:')
|
||||
{
|
||||
$parts['admin'] = 1;
|
||||
$uri = substr($uri, 6);
|
||||
}
|
||||
elseif (substr($uri, 0, 5) == 'site:')
|
||||
{
|
||||
$uri = substr($uri, 5);
|
||||
}
|
||||
elseif (substr($uri, 0, 4) == 'any:')
|
||||
{
|
||||
$parts['admin'] = -1;
|
||||
$uri = substr($uri, 4);
|
||||
}
|
||||
|
||||
if (empty($uri))
|
||||
{
|
||||
return $parts;
|
||||
}
|
||||
|
||||
$uriParts = explode('/', $uri, 3);
|
||||
$partCount = count($uriParts);
|
||||
|
||||
if ($partCount >= 1)
|
||||
{
|
||||
$parts['component'] = $uriParts[0];
|
||||
}
|
||||
|
||||
if ($partCount >= 2)
|
||||
{
|
||||
$parts['view'] = $uriParts[1];
|
||||
}
|
||||
|
||||
if ($partCount >= 3)
|
||||
{
|
||||
$parts['template'] = $uriParts[2];
|
||||
}
|
||||
|
||||
return $parts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves a view template URI (e.g. any:com_foobar/Items/cheese) to an absolute filesystem path
|
||||
* (e.g. /var/www/html/administrator/components/com_foobar/View/Items/tmpl/cheese.php)
|
||||
*
|
||||
* @param string $uri The view template URI to parse
|
||||
* @param string $layoutTemplate The layout template override of the View class
|
||||
* @param array $extraPaths Any extra lookup paths where we'll be looking for this view template
|
||||
* @param bool $noOverride If true we will not load Joomla! template overrides
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function resolveUriToPath($uri, $layoutTemplate = '', array $extraPaths = [], $noOverride = false)
|
||||
{
|
||||
// Parse the URI into its parts
|
||||
$parts = $this->parseTemplateUri($uri);
|
||||
|
||||
// Get some useful values
|
||||
$isAdmin = $this->container->platform->isBackend() ? 1 : 0;
|
||||
$componentPaths = $this->container->platform->getComponentBaseDirs($parts['component']);
|
||||
$templatePath = $this->container->platform->getTemplateOverridePath($parts['component']);
|
||||
|
||||
// Get the lookup paths
|
||||
$paths = [];
|
||||
|
||||
// If we are on the correct side of the application or we have an "any:" URI look for a template override
|
||||
if (!$noOverride && (($parts['admin'] == -1) || ($parts['admin'] == $isAdmin)))
|
||||
{
|
||||
$paths[] = $templatePath . '/' . $parts['view'];
|
||||
}
|
||||
|
||||
// Add the requested side of the application
|
||||
$requestedAdmin = ($parts['admin'] == -1) ? $isAdmin : $parts['admin'];
|
||||
|
||||
$paths[] = ($requestedAdmin ? $componentPaths['admin'] : $componentPaths['site']) . '/ViewTemplates/' . $parts['view'];
|
||||
$paths[] = ($requestedAdmin ? $componentPaths['admin'] : $componentPaths['site']) . '/View/' . $parts['view'] . '/tmpl';
|
||||
|
||||
// Add the other side of the application for "any:" URIs
|
||||
if ($parts['admin'] == -1)
|
||||
{
|
||||
$paths[] = ($requestedAdmin ? $componentPaths['site'] : $componentPaths['admin']) . '/ViewTemplates/' . $parts['view'];
|
||||
$paths[] = ($requestedAdmin ? $componentPaths['site'] : $componentPaths['admin']) . '/View/' . $parts['view'] . '/tmpl';
|
||||
}
|
||||
|
||||
// Add extra paths
|
||||
if (!empty($extraPaths))
|
||||
{
|
||||
$paths = array_merge($paths, $extraPaths);
|
||||
}
|
||||
|
||||
// Remove duplicate paths
|
||||
$paths = array_unique($paths);
|
||||
|
||||
// Look for a template layout override
|
||||
if (!empty($layoutTemplate) && ($layoutTemplate != '_') && ($layoutTemplate != $parts['template']))
|
||||
{
|
||||
$apath = array_shift($paths);
|
||||
array_unshift($paths, str_replace($parts['template'], $layoutTemplate, $apath));
|
||||
}
|
||||
|
||||
// Get the Joomla! version template suffixes
|
||||
$jVersionSuffixes = array_merge($this->container->platform->getTemplateSuffixes(), ['']);
|
||||
|
||||
// Get the renderer name suffixes
|
||||
$rendererNameSuffixes = [
|
||||
'.' . $this->container->renderer->getInformation()->name,
|
||||
'',
|
||||
];
|
||||
|
||||
$filesystem = $this->container->filesystem;
|
||||
|
||||
foreach ($this->extensions as $extension)
|
||||
{
|
||||
foreach ($jVersionSuffixes as $JVersionSuffix)
|
||||
{
|
||||
foreach ($rendererNameSuffixes as $rendererNameSuffix)
|
||||
{
|
||||
$filenameToFind = $parts['template'] . $JVersionSuffix . $rendererNameSuffix . $extension;
|
||||
|
||||
$fileName = $filesystem->pathFind($paths, $filenameToFind);
|
||||
|
||||
if ($fileName)
|
||||
{
|
||||
return $fileName;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If no view template was found for the component fall back to FOF's core Blade templates -- located in
|
||||
* <libdir>/ViewTemplates/<viewName>/<templateName> -- and their template overrides.
|
||||
*/
|
||||
$paths = [];
|
||||
$paths[] = $this->container->platform->getTemplateOverridePath('lib_fof30') . '/' . $parts['view'];
|
||||
$paths[] = realpath(__DIR__ . '/..') . '/ViewTemplates/' . $parts['view'];
|
||||
|
||||
foreach ($jVersionSuffixes as $JVersionSuffix)
|
||||
{
|
||||
foreach ($rendererNameSuffixes as $rendererNameSuffix)
|
||||
{
|
||||
$filenameToFind = $parts['template'] . $JVersionSuffix . $rendererNameSuffix . '.blade.php';
|
||||
|
||||
$fileName = $filesystem->pathFind($paths, $filenameToFind);
|
||||
|
||||
if (!empty($fileName))
|
||||
{
|
||||
return $fileName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new RuntimeException(Text::sprintf('JLIB_APPLICATION_ERROR_LAYOUTFILE_NOT_FOUND', $uri), 500);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of view template extensions
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getExtensions()
|
||||
{
|
||||
return $this->extensions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the list of view template extensions
|
||||
*
|
||||
* @param array $extensions
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setExtensions(array $extensions)
|
||||
{
|
||||
$this->extensions = $extensions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an extension to the list of view template extensions
|
||||
*
|
||||
* @param string $extension
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addExtension($extension)
|
||||
{
|
||||
if (empty($extension))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (substr($extension, 0, 1) != '.')
|
||||
{
|
||||
$extension = '.' . $extension;
|
||||
}
|
||||
|
||||
if (!in_array($extension, $this->extensions))
|
||||
{
|
||||
$this->extensions[] = $extension;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an extension from the list of view template extensions
|
||||
*
|
||||
* @param string $extension
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function removeExtension($extension)
|
||||
{
|
||||
if (empty($extension))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (substr($extension, 0, 1) != '.')
|
||||
{
|
||||
$extension = '.' . $extension;
|
||||
}
|
||||
|
||||
if (!in_array($extension, $this->extensions))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$pos = array_search($extension, $this->extensions);
|
||||
unset ($this->extensions[$pos]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default layout name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getDefaultLayout()
|
||||
{
|
||||
return $this->defaultLayout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the default layout name
|
||||
*
|
||||
* @param string $defaultLayout
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setDefaultLayout($defaultLayout)
|
||||
{
|
||||
$this->defaultLayout = $defaultLayout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default subtemplate name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getDefaultTpl()
|
||||
{
|
||||
return $this->defaultTpl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the default subtemplate name
|
||||
*
|
||||
* @param string $defaultTpl
|
||||
*/
|
||||
public function setDefaultTpl($defaultTpl)
|
||||
{
|
||||
$this->defaultTpl = $defaultTpl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the "strict view" flag. When the flag is false we will look for the view template in both the
|
||||
* singularised and pluralised view. If it's true we will only look for the view template in the view
|
||||
* specified in getViewTemplateUris.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function isStrictView()
|
||||
{
|
||||
return $this->strictView;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the "strict view" flag. When the flag is false we will look for the view template in both the
|
||||
* singularised and pluralised view. If it's true we will only look for the view template in the view
|
||||
* specified in getViewTemplateUris.
|
||||
*
|
||||
* @param boolean $strictView
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setStrictView($strictView)
|
||||
{
|
||||
$this->strictView = $strictView;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the "strict template" flag. When the flag is false we will look for a view template with or without the
|
||||
* subtemplate defined in getViewTemplateUris. If it's true we will only look for the subtemplate specified.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function isStrictTpl()
|
||||
{
|
||||
return $this->strictTpl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the "strict template" flag. When the flag is false we will look for a view template with or without the
|
||||
* subtemplate defined in getViewTemplateUris. If it's true we will only look for the subtemplate specified.
|
||||
*
|
||||
* @param boolean $strictTpl
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setStrictTpl($strictTpl)
|
||||
{
|
||||
$this->strictTpl = $strictTpl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the "strict layout" flag. When the flag is false we will look for a view template with both the specified
|
||||
* and the default template name in getViewTemplateUris. When true we will only look for the specified view
|
||||
* template.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function isStrictLayout()
|
||||
{
|
||||
return $this->strictLayout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the "strict layout" flag. When the flag is false we will look for a view template with both the specified
|
||||
* and the default template name in getViewTemplateUris. When true we will only look for the specified view
|
||||
* template.
|
||||
*
|
||||
* @param boolean $strictLayout
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setStrictLayout($strictLayout)
|
||||
{
|
||||
$this->strictLayout = $strictLayout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the application side prefix which will be used by default in getViewTemplateUris. It can be one of:
|
||||
* site Public front-end
|
||||
* admin Administrator back-end
|
||||
* auto Automatically figure out if it should be site or admin
|
||||
* any First look in the current application side, then look on the other side of the application
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getSidePrefix()
|
||||
{
|
||||
return $this->sidePrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the application side prefix which will be used by default in getViewTemplateUris. It can be one of:
|
||||
* site Public front-end
|
||||
* admin Administrator back-end
|
||||
* auto Automatically figure out if it should be site or admin
|
||||
* any First look in the current application side, then look on the other side of the application
|
||||
*
|
||||
* @param string $sidePrefix
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setSidePrefix($sidePrefix)
|
||||
{
|
||||
$sidePrefix = strtolower($sidePrefix);
|
||||
$sidePrefix = trim($sidePrefix);
|
||||
|
||||
if (!in_array($sidePrefix, ['site', 'admin', 'auto', 'any']))
|
||||
{
|
||||
$sidePrefix = 'auto';
|
||||
}
|
||||
|
||||
$this->sidePrefix = $sidePrefix;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user