Файловый менеджер - Редактировать - /home/wuectly/www/03cbe/View.zip
Назад
PK t!]4h) ) Engine/BladeEngine.phpnu &1i� <?php /** * @package FOF * @copyright Copyright (c)2010-2020 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; } } PK t!]TqP� � Engine/CompilingEngine.phpnu &1i� <?php /** * @package FOF * @copyright Copyright (c)2010-2020 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); } } } PK t!]}�(r� � Engine/PhpEngine.phpnu &1i� <?php /** * @package FOF * @copyright Copyright (c)2010-2020 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, ]; } } PK t!]��c�� � Engine/EngineInterface.phpnu &1i� <?php /** * @package FOF * @copyright Copyright (c)2010-2020 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 = []); } PK t!]�N�u Engine/AbstractEngine.phpnu &1i� <?php /** * @package FOF * @copyright Copyright (c)2010-2020 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' => '', ]; } } PK t!]��s s Exception/EmptyStack.phpnu &1i� <?php /** * @package FOF * @copyright Copyright (c)2010-2020 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); } } PK t!] ��| | Exception/ModelNotFound.phpnu &1i� <?php /** * @package FOF * @copyright Copyright (c)2010-2020 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); } } PK t!]�ФS� � # Exception/UnrecognisedExtension.phpnu &1i� <?php /** * @package FOF * @copyright Copyright (c)2010-2020 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); } } PK t!](�i� Exception/CannotGetName.phpnu &1i� <?php /** * @package FOF * @copyright Copyright (c)2010-2020 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); } } PK t!]�H�t� � Exception/PossiblySuhosin.phpnu &1i� <?php /** * @package FOF * @copyright Copyright (c)2010-2020 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); } } PK t!]�1.� � Exception/AccessForbidden.phpnu &1i� <?php /** * @package FOF * @copyright Copyright (c)2010-2020 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); } } PK t!]6U�� � Compiler/CompilerInterface.phpnu &1i� <?php /** * @package FOF * @copyright Copyright (c)2010-2020 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(); } PK t!]J�j��c �c Compiler/Blade.phpnu &1i� <?php /** * @package FOF * @copyright Copyright (c)2010-2020 Nicholas K. Dionysopoulos / Akeeba Ltd * @license GNU General Public License version 2, or later */ namespace FOF30\View\Compiler; defined('_JEXEC') || die; use FOF30\Container\Container; class Blade implements CompilerInterface { /** * Are the results of this engine cacheable? * * @var bool */ protected $isCacheable = true; /** * The extension of the template files supported by this compiler * * @var string * @since 3.3.1 */ protected $fileExtension = 'blade.php'; /** * All of the registered compiler extensions. * * @var array */ protected $extensions = []; /** * The file currently being compiled. * * @var string */ protected $path; /** * All of the available compiler functions. Each one is called against every HTML block in the template. * * @var array */ protected $compilers = [ 'Extensions', 'Statements', 'Comments', 'Echos', ]; /** * Array of opening and closing tags for escaped echos. * * @var array */ protected $contentTags = ['{{', '}}']; /** * Array of opening and closing tags for escaped echos. * * @var array */ protected $escapedTags = ['{{{', '}}}']; /** * Array of footer lines to be added to template. * * @var array */ protected $footer = []; /** * Counter to keep track of nested forelse statements. * * @var int */ protected $forelseCounter = 0; /** * The FOF container we are attached to * * @var Container */ protected $container; /** * Should I use the PHP Tokenizer extension to compile Blade templates? Default is true and is preferable. We expect * this to be false only on bad quality hosts. It can be overridden with Reflection for testing purposes. * * @var bool */ protected $usingTokenizer = false; public function __construct(Container $container) { $this->container = $container; $this->usingTokenizer = false; if (function_exists('token_get_all') && defined('T_INLINE_HTML')) { $this->usingTokenizer = true; } } /** * Report if the PHP Tokenizer extension is being used * * @return bool */ public function isUsingTokenizer() { return $this->usingTokenizer; } /** * 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() { if (defined('JDEBUG') && JDEBUG) { return false; } return $this->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 = []) { $this->footer = []; $fileData = @file_get_contents($path); if ($path) { $this->setPath($path); } return $this->compileString($fileData); } /** * Get the path currently being compiled. * * @return string */ public function getPath() { return $this->path; } /** * Set the path currently being compiled. * * @param string $path * * @return void */ public function setPath($path) { $this->path = $path; } /** * Compile the given Blade template contents. * * @param string $value * * @return string */ public function compileString($value) { $result = ''; if ($this->usingTokenizer) { // Here we will loop through all of the tokens returned by the Zend lexer and // parse each one into the corresponding valid PHP. We will then have this // template as the correctly rendered PHP that can be rendered natively. foreach (token_get_all($value) as $token) { $result .= is_array($token) ? $this->parseToken($token) : $token; } } else { foreach ($this->compilers as $type) { $value = $this->{"compile{$type}"}($value); } $result .= $value; } // If there are any footer lines that need to get added to a template we will // add them here at the end of the template. This gets used mainly for the // template inheritance via the extends keyword that should be appended. if (count($this->footer) > 0) { $result = ltrim($result, PHP_EOL) . PHP_EOL . implode(PHP_EOL, array_reverse($this->footer)); } return $result; } /** * Compile the default values for the echo statement. * * @param string $value * * @return string */ public function compileEchoDefaults($value) { return preg_replace('/^(?=\$)(.+?)(?:\s+or\s+)(.+?)$/s', 'isset($1) ? $1 : $2', $value); } /** * Register a custom Blade compiler. Using a tag or not changes the behavior of this method when you try to redefine * an existing custom Blade compiler. * * If you use a tag which already exists the old compiler is replaced by the new one you are defining. * * If you do not use a tag, the new compiler you are defining will always be added to the bottom of the list. That * is to say, if another compiler would be matching the same function name (e.g. `@foobar`) it would get compiled by * the first compiler, the one already set, not the one you are defining now. You are suggested to always use a tag * for this reason. * * Finally, note that custom Blade compilers are compiled last. This means that you cannot override a core Blade * compiler with a custom one. If you need to do that you need to create a new Compiler class -- probably extending * this one -- and override the protected compiler methods. Remember to also create a custom Container and override * its 'blade' key with a callable which returns an object of your custom class. * * @param callable $compiler * @param string $tag Optional. Give the callable a tag you can look for with hasExtensionByName * * @return void */ public function extend($compiler, $tag = null) { if (!is_null($tag)) { $this->extensions[$tag] = $compiler; return; } $this->extensions[] = $compiler; } /** * Look if a custom Blade compiler exists given its optional tag name. * * @param string $tag * * @return bool */ public function hasExtension($tag) { return array_key_exists($tag, $this->extensions); } /** * Remove a custom BLade compiler given its optional tag name * * @param string $tag */ public function removeExtension($tag) { if (!$this->hasExtension($tag)) { return; } unset ($this->extensions[$tag]); } /** * Get the regular expression for a generic Blade function. * * @param string $function * * @return string */ public function createMatcher($function) { return '/(?<!\w)(\s*)@' . $function . '(\s*\(.*\))/'; } /** * Get the regular expression for a generic Blade function. * * @param string $function * * @return string */ public function createOpenMatcher($function) { return '/(?<!\w)(\s*)@' . $function . '(\s*\(.*)\)/'; } /** * Create a plain Blade matcher. * * @param string $function * * @return string */ public function createPlainMatcher($function) { return '/(?<!\w)(\s*)@' . $function . '(\s*)/'; } /** * Sets the escaped content tags used for the compiler. * * @param string $openTag * @param string $closeTag * * @return void */ public function setEscapedContentTags($openTag, $closeTag) { $this->setContentTags($openTag, $closeTag, true); } /** * Gets the content tags used for the compiler. * * @return string */ public function getContentTags() { return $this->getTags(); } /** * Sets the content tags used for the compiler. * * @param string $openTag * @param string $closeTag * @param bool $escaped * * @return void */ public function setContentTags($openTag, $closeTag, $escaped = false) { $property = ($escaped === true) ? 'escapedTags' : 'contentTags'; $this->{$property} = [preg_quote($openTag), preg_quote($closeTag)]; } /** * Gets the escaped content tags used for the compiler. * * @return string */ public function getEscapedContentTags() { return $this->getTags(true); } /** * Returns the file extension supported by this compiler * * @return string * * @since 3.3.1 */ public function getFileExtension() { return $this->fileExtension; } /** * Parse the tokens from the template. * * @param array $token * * @return string */ protected function parseToken($token) { [$id, $content] = $token; if ($id == T_INLINE_HTML) { foreach ($this->compilers as $type) { $content = $this->{"compile{$type}"}($content); } } return $content; } /** * Execute the user defined extensions. * * @param string $value * * @return string */ protected function compileExtensions($value) { foreach ($this->extensions as $compiler) { $value = call_user_func($compiler, $value, $this); } return $value; } /** * Compile Blade comments into valid PHP. * * @param string $value * * @return string */ protected function compileComments($value) { $pattern = sprintf('/%s--((.|\s)*?)--%s/', $this->contentTags[0], $this->contentTags[1]); return preg_replace($pattern, '<?php /*$1*/ ?>', $value); } /** * Compile Blade echos into valid PHP. * * @param string $value * * @return string */ protected function compileEchos($value) { $difference = strlen($this->contentTags[0]) - strlen($this->escapedTags[0]); if ($difference > 0) { return $this->compileEscapedEchos($this->compileRegularEchos($value)); } return $this->compileRegularEchos($this->compileEscapedEchos($value)); } /** * Compile Blade Statements that start with "@" * * @param string $value * * @return mixed */ protected function compileStatements($value) { return preg_replace_callback('/\B@(\w+)([ \t]*)(\( ( (?>[^()]+) | (?3) )* \))?/x', [ $this, 'compileStatementsCallback', ], $value); } /** * Callback for compileStatements, since $this is not allowed in Closures under PHP 5.3. * * @param $match * * @return string */ protected function compileStatementsCallback($match) { if (method_exists($this, $method = 'compile' . ucfirst($match[1]))) { $match[0] = $this->$method(array_get($match, 3)); } return isset($match[3]) ? $match[0] : $match[0] . $match[2]; } /** * Compile the "regular" echo statements. * * @param string $value * * @return string */ protected function compileRegularEchos($value) { $pattern = sprintf('/(@)?%s\s*(.+?)\s*%s(\r?\n)?/s', $this->contentTags[0], $this->contentTags[1]); return preg_replace_callback($pattern, [$this, 'compileRegularEchosCallback'], $value); } /** * Callback for compileRegularEchos, since $this is not allowed in Closures under PHP 5.3. * * @param array $matches * * @return string */ protected function compileRegularEchosCallback($matches) { $whitespace = empty($matches[3]) ? '' : $matches[3] . $matches[3]; return $matches[1] ? substr($matches[0], 1) : '<?php echo ' . $this->compileEchoDefaults($matches[2]) . '; ?>' . $whitespace; } /** * Compile the escaped echo statements. * * @param string $value * * @return string */ protected function compileEscapedEchos($value) { $pattern = sprintf('/%s\s*(.+?)\s*%s(\r?\n)?/s', $this->escapedTags[0], $this->escapedTags[1]); return preg_replace_callback($pattern, [$this, 'compileEscapedEchosCallback'], $value); } /** * Callback for compileEscapedEchos, since $this is not allowed in Closures under PHP 5.3. * * @param array $matches * * @return string */ protected function compileEscapedEchosCallback($matches) { $whitespace = empty($matches[2]) ? '' : $matches[2] . $matches[2]; return '<?php echo $this->escape(' . $this->compileEchoDefaults($matches[1]) . '); ?>' . $whitespace; } /** * Compile the each statements into valid PHP. * * @param string $expression * * @return string */ protected function compileEach($expression) { return "<?php echo \$this->renderEach{$expression}; ?>"; } /** * Compile the yield statements into valid PHP. * * @param string $expression * * @return string */ protected function compileYield($expression) { return "<?php echo \$this->yieldContent{$expression}; ?>"; } /** * Compile the show statements into valid PHP. * * @param string $expression * * @return string */ protected function compileShow($expression) { return "<?php echo \$this->yieldSection(); ?>"; } /** * Compile the section statements into valid PHP. * * @param string $expression * * @return string */ protected function compileSection($expression) { return "<?php \$this->startSection{$expression}; ?>"; } /** * Compile the append statements into valid PHP. * * @param string $expression * * @return string */ protected function compileAppend($expression) { return "<?php \$this->appendSection(); ?>"; } /** * Compile the end-section statements into valid PHP. * * @param string $expression * * @return string */ protected function compileEndsection($expression) { return "<?php \$this->stopSection(); ?>"; } /** * Compile the stop statements into valid PHP. * * @param string $expression * * @return string */ protected function compileStop($expression) { return "<?php \$this->stopSection(); ?>"; } /** * Compile the overwrite statements into valid PHP. * * @param string $expression * * @return string */ protected function compileOverwrite($expression) { return "<?php \$this->stopSection(true); ?>"; } /** * Compile the unless statements into valid PHP. * * @param string $expression * * @return string */ protected function compileUnless($expression) { return "<?php if ( ! $expression): ?>"; } /** * Compile the end unless statements into valid PHP. * * @param string $expression * * @return string */ protected function compileEndunless($expression) { return "<?php endif; ?>"; } /** * Compile the end repeatable statements into valid PHP. * * @param string $expression * * @return string */ protected function compileRepeatable($expression) { $expression = trim($expression, '()'); $parts = explode(',', $expression, 2); $functionName = '_fof_blade_repeatable_' . md5($this->path . trim($parts[0])); $argumentsList = $parts[1] ?? ''; return "<?php @\$$functionName = function($argumentsList) { ?>"; } /** * Compile the end endRepeatable statements into valid PHP. * * @param string $expression * * @return string */ protected function compileEndRepeatable($expression) { return "<?php }; ?>"; } /** * Compile the end yieldRepeatable statements into valid PHP. * * @param string $expression * * @return string */ protected function compileYieldRepeatable($expression) { $expression = trim($expression, '()'); $parts = explode(',', $expression, 2); $functionName = '_fof_blade_repeatable_' . md5($this->path . trim($parts[0])); $argumentsList = $parts[1] ?? ''; return "<?php \$$functionName($argumentsList); ?>"; } /** * Compile the lang statements into valid PHP. * * @param string $expression * * @return string */ protected function compileLang($expression) { return "<?php echo \\Joomla\\CMS\\Language\\Text::_$expression; ?>"; } /** * Compile the sprintf statements into valid PHP. * * @param string $expression * * @return string */ protected function compileSprintf($expression) { return "<?php echo \\Joomla\\CMS\\Language\\Text::sprintf$expression; ?>"; } /** * Compile the plural statements into valid PHP. * * e.g. @plural('COM_FOOBAR_N_ITEMS_SAVED', $countItemsSaved) * * @param string $expression * * @return string * @see JText::plural() * */ protected function compilePlural($expression) { return "<?php echo \\Joomla\\CMS\\Language\\Text::plural$expression; ?>"; } /** * Compile the token statements into valid PHP. * * @param string $expression * * @return string */ protected function compileToken($expression) { return "<?php echo \$this->container->platform->getToken(true); ?>"; } /** * Compile the else statements into valid PHP. * * @param string $expression * * @return string */ protected function compileElse($expression) { return "<?php else: ?>"; } /** * Compile the for statements into valid PHP. * * @param string $expression * * @return string */ protected function compileFor($expression) { return "<?php for{$expression}: ?>"; } /** * Compile the foreach statements into valid PHP. * * @param string $expression * * @return string */ protected function compileForeach($expression) { return "<?php foreach{$expression}: ?>"; } /** * Compile the forelse statements into valid PHP. * * @param string $expression * * @return string */ protected function compileForelse($expression) { $empty = '$__empty_' . ++$this->forelseCounter; return "<?php {$empty} = true; foreach{$expression}: {$empty} = false; ?>"; } /** * Compile the if statements into valid PHP. * * @param string $expression * * @return string */ protected function compileIf($expression) { return "<?php if{$expression}: ?>"; } /** * Compile the else-if statements into valid PHP. * * @param string $expression * * @return string */ protected function compileElseif($expression) { return "<?php elseif{$expression}: ?>"; } /** * Compile the forelse statements into valid PHP. * * @param string $expression * * @return string */ protected function compileEmpty($expression) { $empty = '$__empty_' . $this->forelseCounter--; return "<?php endforeach; if ({$empty}): ?>"; } /** * Compile the while statements into valid PHP. * * @param string $expression * * @return string */ protected function compileWhile($expression) { return "<?php while{$expression}: ?>"; } /** * Compile the end-while statements into valid PHP. * * @param string $expression * * @return string */ protected function compileEndwhile($expression) { return "<?php endwhile; ?>"; } /** * Compile the end-for statements into valid PHP. * * @param string $expression * * @return string */ protected function compileEndfor($expression) { return "<?php endfor; ?>"; } /** * Compile the end-for-each statements into valid PHP. * * @param string $expression * * @return string */ protected function compileEndforeach($expression) { return "<?php endforeach; ?>"; } /** * Compile the end-if statements into valid PHP. * * @param string $expression * * @return string */ protected function compileEndif($expression) { return "<?php endif; ?>"; } /** * Compile the end-for-else statements into valid PHP. * * @param string $expression * * @return string */ protected function compileEndforelse($expression) { return "<?php endif; ?>"; } /** * Compile the extends statements into valid PHP. * * @param string $expression * * @return string */ protected function compileExtends($expression) { if (starts_with($expression, '(')) { $expression = substr($expression, 1, -1); } $data = "<?php echo \$this->loadAnyTemplate($expression); ?>"; $this->footer[] = $data; return ''; } /** * Compile the include statements into valid PHP. * * @param string $expression * * @return string */ protected function compileInclude($expression) { if (starts_with($expression, '(')) { $expression = substr($expression, 1, -1); } return "<?php echo \$this->loadAnyTemplate($expression); ?>"; } /** * Compile the jlayout statements into valid PHP. * * @param string $expression * * @return string */ protected function compileJlayout($expression) { if (starts_with($expression, '(')) { $expression = substr($expression, 1, -1); } return "<?php echo \\FOF30\\Layout\\LayoutHelper::render(\$this->container, $expression); ?>"; } /** * Compile the stack statements into the content * * @param string $expression * * @return string */ protected function compileStack($expression) { return "<?php echo \$this->yieldContent{$expression}; ?>"; } /** * Compile the push statements into valid PHP. * * @param string $expression * * @return string */ protected function compilePush($expression) { return "<?php \$this->startSection{$expression}; ?>"; } /** * Compile the endpush statements into valid PHP. * * @param string $expression * * @return string */ protected function compileEndpush($expression) { return "<?php \$this->appendSection(); ?>"; } /** * Compile the route statements into valid PHP. * * @param string $expression * * @return string */ protected function compileRoute($expression) { return "<?php echo \$this->container->template->route{$expression}; ?>"; } /** * Compile the css statements into valid PHP. * * @param string $expression * * @return string */ protected function compileCss($expression) { return "<?php \$this->addCssFile{$expression}; ?>"; } /** * Compile the inlineCss statements into valid PHP. * * @param string $expression * * @return string */ protected function compileInlineCss($expression) { return "<?php \$this->addCssInline{$expression}; ?>"; } /** * Compile the inlineJs statements into valid PHP. * * @param string $expression * * @return string */ protected function compileInlineJs($expression) { return "<?php \$this->addJavascriptInline{$expression}; ?>"; } /** * Compile the js statements into valid PHP. * * @param string $expression * * @return string */ protected function compileJs($expression) { return "<?php \$this->addJavascriptFile{$expression}; ?>"; } /** * Compile the jhtml statements into valid PHP. * * @param string $expression * * @return string */ protected function compileJhtml($expression) { return "<?php echo \\Joomla\\CMS\\HTML\\HTMLHelper::_{$expression}; ?>"; } /** * Compile the `sortgrid` statements into valid PHP. * * @param string $expression * * @return string * * @since 3.3.0 */ protected function compileSortgrid($expression) { return "<?php echo \\FOF30\\Utils\\FEFHelper\\BrowseView::sortGrid{$expression} ?>"; } /** * Compile the `fieldtitle` statements into valid PHP. * * @param string $expression * * @return string * * @since 3.3.0 */ protected function compileFieldtitle($expression) { return "<?php echo \\FOF30\\Utils\\FEFHelper\\BrowseView::fieldLabel{$expression} ?>"; } /** * Compile the `modelfilter($localField, [$modelTitleField, $modelName, $placeholder, $params])` statements into * valid PHP. * * @param string $expression * * @return string * * @since 3.3.0 */ protected function compileModelfilter($expression) { return "<?php echo \\FOF30\\Utils\\FEFHelper\\BrowseView::modelFilter{$expression} ?>"; } /** * Compile the `selectfilter($localField, $options [, $placeholder, $params])` statements into valid PHP. * * @param string $expression * * @return string * * @since 3.3.0 */ protected function compileSelectfilter($expression) { return "<?php echo \\FOF30\\Utils\\FEFHelper\\BrowseView::selectFilter{$expression} ?>"; } /** * Compile the `searchfilter($localField, $searchField = null, $placeholder = null, array $attributes = [])` * statements into valid PHP. * * @param string $expression * * @return string * * @since 3.3.0 */ protected function compileSearchfilter($expression) { return "<?php echo \\FOF30\\Utils\\FEFHelper\\BrowseView::searchFilter{$expression} ?>"; } /** * Compile the media statements into valid PHP. * * @param string $expression * * @return string */ protected function compileMedia($expression) { return "<?php echo \$this->container->template->parsePath{$expression}; ?>"; } /** * Compile the modules statements into valid PHP. * * @param string $expression * * @return string */ protected function compileModules($expression) { return "<?php echo \$this->container->template->loadPosition{$expression}; ?>"; } /** * Compile the module statements into valid PHP. * * @param string $expression * * @return string */ protected function compileModule($expression) { return "<?php echo \$this->container->template->loadModule{$expression}; ?>"; } /** * Compile the editor statements into valid PHP. * * @param string $expression * * @return string */ protected function compileEditor($expression) { return '<?php echo \\Joomla\\CMS\\Editor\\Editor::getInstance($this->container->platform->getConfig()->get(\'editor\', \'tinymce\'))' . '->display' . $expression . '; ?>'; } /** * Gets the tags used for the compiler. * * @param bool $escaped * * @return array */ protected function getTags($escaped = false) { $tags = $escaped ? $this->escapedTags : $this->contentTags; return array_map('stripcslashes', $tags); } } PK t!]ۡ;�B@ B@ ViewTemplateFinder.phpnu &1i� <?php /** * @package FOF * @copyright Copyright (c)2010-2020 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; } } PK t!]��㘇 �� View.phpnu &1i� <?php /** * @package FOF * @copyright Copyright (c)2010-2020 Nicholas K. Dionysopoulos / Akeeba Ltd * @license GNU General Public License version 2, or later */ namespace FOF30\View; defined('_JEXEC') || die; use ErrorException; use Exception; use FOF30\Container\Container; use FOF30\Input\Input; use FOF30\Model\Model; use FOF30\View\Engine\EngineInterface; use FOF30\View\Engine\PhpEngine; use FOF30\View\Exception\CannotGetName; use FOF30\View\Exception\EmptyStack; use FOF30\View\Exception\ModelNotFound; use FOF30\View\Exception\UnrecognisedExtension; use Joomla\CMS\Language\Text; /** * Class View * * A generic MVC view implementation * * @property-read Input $input The input object (magic __get returns the Input from the Container) */ class View { public $baseurl = null; /** * Current or most recently performed task. * Currently public, it should be reduced to protected in the future * * @var string */ public $task; /** * The mapped task that was performed. * Currently public, it should be reduced to protected in the future * * @var string */ public $doTask; /** * The name of the view * * @var array */ protected $name = null; /** * Registered models * * @var array */ protected $modelInstances = []; /** * The default model * * @var string */ protected $defaultModel = null; /** * Layout name * * @var string */ protected $layout = 'default'; /** * Layout template * * @var string */ protected $layoutTemplate = '_'; /** * The set of search directories for view templates * * @var array */ protected $templatePaths = []; /** * The name of the default template source file. * * @var string */ protected $template = null; /** * The output of the template script. * * @var string */ protected $output = null; /** * A cached copy of the configuration * * @var array */ protected $config = []; /** * The container attached to this view * * @var Container */ protected $container; /** * The object used to locate view templates in the filesystem * * @var ViewTemplateFinder */ protected $viewFinder = null; /** * Used when loading template files to avoid variable scope issues * * @var null */ protected $_tempFilePath = null; /** * Should I run the pre-render step? * * @var boolean */ protected $doPreRender = true; /** * Should I run the post-render step? * * @var boolean */ protected $doPostRender = true; /** * Maps view template extensions to view engine classes * * @var array */ protected $viewEngineMap = [ '.blade.php' => 'FOF30\\View\\Engine\\BladeEngine', '.php' => 'FOF30\\View\\Engine\\PhpEngine', ]; /** * All of the finished, captured sections. * * @var array */ protected $sections = []; /** * The stack of in-progress sections. * * @var array */ protected $sectionStack = []; /** * The number of active rendering operations. * * @var int */ protected $renderCount = 0; /** * Aliases of view templates. For example: * * array('userProfile' => 'site://com_foobar/users/profile') * * allows you to do something like $this->loadAnyTemplate('userProfile') to display the frontend view template * site://com_foobar/users/profile. You can also alias one view template with another, e.g. * 'site://com_something/users/profile' => 'admin://com_foobar/clients/record' * * @var array */ protected $viewTemplateAliases = []; /** * Constructor. * * The $config array can contain the following overrides: * name string The name of the view (defaults to the view class name) * template_path string The path of the layout directory * layout string The layout for displaying the view * viewFinder ViewTemplateFinder The object used to locate view templates in the filesystem * viewEngineMap array Maps view template extensions to view engine classes * * @param Container $container The container we belong to * @param array $config The configuration overrides for the view * * @return View */ public function __construct(Container $container, array $config = []) { $this->container = $container; $this->config = $config; // Get the view name if (isset($this->config['name'])) { $this->name = $this->config['name']; } $this->name = $this->getName(); // Set the default template search path if (array_key_exists('template_path', $this->config)) { // User-defined dirs $this->setTemplatePath($this->config['template_path']); } else { $this->setTemplatePath($this->container->thisPath . '/View/' . ucfirst($this->name) . '/tmpl'); } // Set the layout if (array_key_exists('layout', $this->config)) { $this->setLayout($this->config['layout']); } // Apply the viewEngineMap if (isset($config['viewEngineMap'])) { // If the overrides are a string convert it to an array first. if (!is_array($config['viewEngineMap'])) { $temp = explode(',', $config['viewEngineMap']); $config['viewEngineMap'] = []; foreach ($temp as $assignment) { $parts = explode('=>', $assignment, 2); if (count($parts) != 2) { continue; } $parts = array_map(function ($x) { return trim($x); }, $parts); $config['viewEngineMap'][$parts[0]] = $parts[1]; } } /** * We want to always have a sane fallback to plain .php template files at the end of the view engine stack. * For this to happen to we need to remove it from the current stack, disallow overriding it in the * viewEngineMap overrides, merge the overrides and then add the fallback at the very end of the stack. * * In previous versions we didn't do that which had two side effects: * 1. It was no longer a fallback, it was in the middle of the stack * 2. Any new template engines using a .something.php extension wouldn't work, see * https://github.com/akeeba/fof/issues/694 */ // Do not allow overriding the fallback .php handler if (isset($config['viewEngineMap']['.php'])) { unset ($config['viewEngineMap']['.php']); } // Temporarily remove the fallback .php handler $phpHandler = $this->viewEngineMap['.php'] ?? PhpEngine::class; unset ($this->viewEngineMap['.php']); // Add the overrides $this->viewEngineMap = array_merge($this->viewEngineMap, $config['viewEngineMap']); // Push the fallback .php handler to the end of the view engine map stack $this->viewEngineMap = array_merge($this->viewEngineMap, [ '.php' => $phpHandler ]); } // Set the ViewFinder $this->viewFinder = $this->container->factory->viewFinder($this); if (isset($config['viewFinder']) && !empty($config['viewFinder']) && is_object($config['viewFinder']) && ($config['viewFinder'] instanceof ViewTemplateFinder)) { $this->viewFinder = $config['viewFinder']; } // Apply the registered view template extensions to the view finder $this->viewFinder->setExtensions(array_keys($this->viewEngineMap)); // Apply the base URL $this->baseurl = $this->container->platform->URIbase(); } /** * Magic get method. Handles magic properties: * $this->input mapped to $this->container->input * * @param string $name The property to fetch * * @return mixed|null */ public function __get($name) { // Handle $this->input if ($name == 'input') { return $this->container->input; } // Property not found; raise error $trace = debug_backtrace(); trigger_error( 'Undefined property via __get(): ' . $name . ' in ' . $trace[0]['file'] . ' on line ' . $trace[0]['line'], E_USER_NOTICE); return null; } /** * 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() { if (empty($this->name)) { $r = null; if (!preg_match('/(.*)\\\\View\\\\(.*)\\\\(.*)/i', get_class($this), $r)) { throw new CannotGetName; } $this->name = $r[2]; } return $this->name; } /** * Escapes a value for output in a view script. * * @param mixed $var The output to escape. * * @return mixed The escaped value. */ public function escape($var) { return htmlspecialchars($var, ENT_COMPAT, 'UTF-8'); } /** * Method to get data from a registered model or a property of the view * * @param string $property The name of the method to call on the Model or the property to get * @param string $default The default value [optional] * @param string $modelName The name of the Model to reference [optional] * * @return mixed The return value of the method */ public function get($property, $default = null, $modelName = null) { // If $model is null we use the default model if (is_null($modelName)) { $model = $this->defaultModel; } else { $model = $modelName; } // First check to make sure the model requested exists if (isset($this->modelInstances[$model])) { // Model exists, let's build the method name $method = 'get' . ucfirst($property); // Does the method exist? if (method_exists($this->modelInstances[$model], $method)) { // The method exists, let's call it and return what we get $result = $this->modelInstances[$model]->$method(); return $result; } else { $result = $this->modelInstances[$model]->$property(); if (is_null($result)) { return $default; } return $result; } } // If the model doesn't exist, try to fetch a View property else { if (@isset($this->$property)) { return $this->$property; } else { return $default; } } } /** * Returns a named Model object * * @param string $name The Model name. If null we'll use the modelName * variable or, if it's empty, the same name as * the Controller * * @return Model The instance of the Model known to this Controller */ public function getModel($name = null) { if (!empty($name)) { $modelName = $name; } elseif (!empty($this->defaultModel)) { $modelName = $this->defaultModel; } else { $modelName = $this->name; } if (!array_key_exists($modelName, $this->modelInstances)) { throw new ModelNotFound($modelName, $this->name); } return $this->modelInstances[$modelName]; } /** * Pushes the default Model to the View * * @param Model $model The model to push */ public function setDefaultModel(Model &$model) { $name = $model->getName(); $this->setDefaultModelName($name); $this->setModel($this->defaultModel, $model); } /** * Set the name of the Model to be used by this View * * @param string $modelName The name of the Model * * @return void */ public function setDefaultModelName($modelName) { $this->defaultModel = $modelName; } /** * Pushes a named model to the View * * @param string $modelName The name of the Model * @param Model $model The actual Model object to push * * @return void */ public function setModel($modelName, Model &$model) { $this->modelInstances[$modelName] = $model; } /** * 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]); $preRenderResult = ''; if ($this->doPreRender) { @ob_start(); $this->preRender(); $preRenderResult = @ob_get_contents(); @ob_end_clean(); } $templateResult = $this->loadTemplate($tpl); $eventName = 'onAfter' . ucfirst($this->doTask); $this->triggerEvent($eventName, [$tpl]); if (is_object($templateResult) && ($templateResult instanceof Exception)) { throw $templateResult; } echo $preRenderResult . $templateResult; if ($this->doPostRender) { $this->postRender(); } return true; } /** * Get the layout. * * @return string The layout name */ public function getLayout() { return $this->layout; } /** * Sets the layout name to use * * @param string $layout The layout name or a string in format <template>:<layout file> * * @return string Previous value. */ public function setLayout($layout) { $previous = $this->layout; if (is_null($layout)) { $layout = 'default'; } if (strpos($layout, ':') === false) { $this->layout = $layout; } else { // Convert parameter to array based on : $temp = explode(':', $layout); $this->layout = $temp[1]; // Set layout template $this->layoutTemplate = $temp[0]; } return $previous; } /** * Our function uses loadAnyTemplate to provide smarter view template loading. * * @param string $tpl The name of the template file to parse * @param boolean $strict Should we use strict naming, i.e. force a non-empty $tpl? * * @return mixed A string if successful, otherwise an Exception */ public function loadTemplate($tpl = null, $strict = false) { $result = ''; $uris = $this->viewFinder->getViewTemplateUris([ 'component' => $this->container->componentName, 'view' => $this->getName(), 'layout' => $this->getLayout(), 'tpl' => $tpl, 'strictTpl' => $strict, ]); foreach ($uris as $uri) { try { $result = $this->loadAnyTemplate($uri); break; } catch (Exception $e) { $result = $e; } } if ($result instanceof Exception) { $this->container->platform->raiseError($result->getCode(), $result->getMessage()); } return $result; } /** * Loads a template given any path. The path is in the format componentPart://componentName/viewName/layoutName, * for example * site:com_example/items/default * admin:com_example/items/default_subtemplate * auto:com_example/things/chair * any:com_example/invoices/printpreview * * @param string $uri The template path * @param array $forceParams A hash array of variables to be extracted in the local scope of the template * file * @param callable $callback A method to post-process the 3ναluα+3d view template (I use leetspeak here * because of bad quality hosts with broken scanners) * @param bool $noOverride If true we will not load Joomla! template overrides * * @return string The output of the template * * @throws Exception When the layout file is not found */ public function loadAnyTemplate($uri = '', $forceParams = [], $callback = null, $noOverride = false) { if (isset($this->viewTemplateAliases[$uri])) { $uri = $this->viewTemplateAliases[$uri]; } $layoutTemplate = $this->getLayoutTemplate(); $extraPaths = []; if (!empty($this->templatePaths)) { $extraPaths = $this->templatePaths; } // First get the raw view template path $path = $this->viewFinder->resolveUriToPath($uri, $layoutTemplate, $extraPaths, $noOverride); // Now get the parsed view template path $this->_tempFilePath = $this->getEngine($path)->get($path, $forceParams); // We will keep track of the amount of views being rendered so we can flush // the section after the complete rendering operation is done. This will // clear out the sections for any separate views that may be rendered. $this->incrementRender(); // Get the processed template $contents = $this->processTemplate($forceParams); // Once we've finished rendering the view, we'll decrement the render count // so that each sections get flushed out next time a view is created and // no old sections are staying around in the memory of an environment. $this->decrementRender(); $response = isset($callback) ? $callback($this, $contents) : null; if (!is_null($response)) { $contents = $response; } // Once we have the contents of the view, we will flush the sections if we are // done rendering all views so that there is nothing left hanging over when // another view gets rendered in the future by the application developer. $this->flushSectionsIfDoneRendering(); return $contents; } /** * Increment the rendering counter. * * @return void */ public function incrementRender() { $this->renderCount++; } /** * Decrement the rendering counter. * * @return void */ public function decrementRender() { $this->renderCount--; } /** * Check if there are no active render operations. * * @return bool */ public function doneRendering() { return $this->renderCount == 0; } /** * Go through a data array and render a subtemplate against each record (think master-detail views). This is * accessible through Blade templates as @each * * @param string $viewTemplate The view template to use for each subitem, format * componentPart://componentName/viewName/layoutName * @param array $data The array of data you want to render. It can be a DataModel\Collection, array, * ... * @param string $eachItemName How to call each item in the loaded subtemplate (passed through $forceParams) * @param string $empty What to display if the array is empty * * @return string */ public function renderEach($viewTemplate, $data, $eachItemName, $empty = 'raw|') { $result = ''; // If is actually data in the array, we will loop through the data and append // an instance of the partial view to the final result HTML passing in the // iterated value of this data array, allowing the views to access them. if (count($data) > 0) { foreach ($data as $key => $value) { $data = ['key' => $key, $eachItemName => $value]; $result .= $this->loadAnyTemplate($viewTemplate, $data); } } // If there is no data in the array, we will render the contents of the empty // view. Alternatively, the "empty view" could be a raw string that begins // with "raw|" for convenience and to let this know that it is a string. Or // a language string starting with text|. else { if (starts_with($empty, 'raw|')) { $result = substr($empty, 4); } elseif (starts_with($empty, 'text|')) { $result = Text::_(substr($empty, 5)); } else { $result = $this->loadAnyTemplate($empty); } } return $result; } /** * Start injecting content into a section. * * @param string $section * @param string $content * * @return void */ public function startSection($section, $content = '') { if ($content === '') { if (ob_start()) { $this->sectionStack[] = $section; } } else { $this->extendSection($section, $content); } } /** * Stop injecting content into a section and return its contents. * * @return string */ public function yieldSection() { return $this->yieldContent($this->stopSection()); } /** * Stop injecting content into a section. * * @param bool $overwrite * * @return string */ public function stopSection($overwrite = false) { if (empty($this->sectionStack)) { // Let's close the output buffering ob_get_clean(); throw new EmptyStack(); } $last = array_pop($this->sectionStack); if ($overwrite) { $this->sections[$last] = ob_get_clean(); } else { $this->extendSection($last, ob_get_clean()); } return $last; } /** * Stop injecting content into a section and append it. * * @return string */ public function appendSection() { if (empty($this->sectionStack)) { // Let's close the output buffering ob_get_clean(); throw new EmptyStack(); } $last = array_pop($this->sectionStack); if (isset($this->sections[$last])) { $this->sections[$last] .= ob_get_clean(); } else { $this->sections[$last] = ob_get_clean(); } return $last; } /** * Get the string contents of a section. * * @param string $section * @param string $default * * @return string */ public function yieldContent($section, $default = '') { $sectionContent = $default; if (isset($this->sections[$section])) { $sectionContent = $this->sections[$section]; } return str_replace('@parent', '', $sectionContent); } /** * Flush all of the section contents. * * @return void */ public function flushSections() { $this->sections = []; $this->sectionStack = []; } /** * Flush all of the section contents if done rendering. * * @return void */ public function flushSectionsIfDoneRendering() { if ($this->doneRendering()) { $this->flushSections(); } } /** * Get the layout template. * * @return string The layout template name */ public function getLayoutTemplate() { return $this->layoutTemplate; } /** * Load a helper file * * @param string $helperClass The last part of the name of the helper * class. * * @return void * * @deprecated 3.0 Just use the class in your code. That's what the autoloader is for. */ public function loadHelper($helperClass = null) { // Get the helper class name $className = '\\' . $this->container->getNamespacePrefix() . 'Helper\\' . ucfirst($helperClass); // This trick autoloads the helper class. We can't instantiate it as // helpers are (supposed to be) abstract classes with static method // interfaces. class_exists($className); } /** * Returns a reference to the container attached to this View * * @return Container */ public function &getContainer() { return $this->container; } public function getTask() { return $this->task; } /** * @param string $task * * @return $this This for chaining */ public function setTask($task) { $this->task = $task; return $this; } public function getDoTask() { return $this->doTask; } /** * @param string $task * * @return $this This for chaining */ public function setDoTask($task) { $this->doTask = $task; return $this; } /** * Sets the pre-render flag * * @param boolean $value True to enable the pre-render step * * @return void */ public function setPreRender($value) { $this->doPreRender = $value; } /** * Sets the post-render flag * * @param boolean $value True to enable the post-render step * * @return void */ public function setPostRender($value) { $this->doPostRender = $value; } /** * Add an alias for a view template. * * @param string $viewTemplate Existing view template, in the format * componentPart://componentName/viewName/layoutName * @param string $alias The alias of the view template (any string will do) * * @return void */ public function alias($viewTemplate, $alias) { $this->viewTemplateAliases[$alias] = $viewTemplate; } /** * 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) { // Add an automatic version if $version is null. For no version parameter pass an empty string to $version. if (is_null($version)) { $version = $this->container->mediaVersion; } $this->container->template->addJS($uri, $defer, $async, $version, $type); return $this; } /** * 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') { $this->container->template->addJSInline($script, $type); return $this; } /** * 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 = []) { // Add an automatic version if $version is null. For no version parameter pass an empty string to $version. if (is_null($version)) { $version = $this->container->mediaVersion; } $this->container->template->addCSS($uri, $version, $type, $media, $attribs); return $this; } /** * 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') { $this->container->template->addCSSInline($css, $type); return $this; } /** * Sets an entire array of search paths for templates or resources. * * @param mixed $path The new search path, or an array of search paths. If null or false, resets to the current * directory only. * * @return void */ protected function setTemplatePath($path) { // Clear out the prior search dirs $this->templatePaths = []; // Actually add the user-specified directories $this->addTemplatePath($path); // Set the alternative template search dir $templatePath = JPATH_THEMES; $fallback = $templatePath . '/' . $this->container->platform->getTemplate() . '/html/' . $this->container->componentName . '/' . $this->name; $this->addTemplatePath($fallback); // Get extra directories through event dispatchers $extraPathsResults = $this->container->platform->runPlugins('onGetViewTemplatePaths', [ $this->container->componentName, $this->getName(), ]); if (is_array($extraPathsResults) && !empty($extraPathsResults)) { foreach ($extraPathsResults as $somePaths) { if (!empty($somePaths)) { foreach ($somePaths as $aPath) { $this->addTemplatePath($aPath); } } } } } /** * Adds to the search path for templates and resources. * * @param mixed $path The directory or stream, or an array of either, to search. * * @return void */ protected function addTemplatePath($path) { // Just force to array $path = (array) $path; // Loop through the path directories foreach ($path as $dir) { // No surrounding spaces allowed! $dir = trim($dir); // Add trailing separators as needed if (substr($dir, -1) != DIRECTORY_SEPARATOR) { // Directory $dir .= DIRECTORY_SEPARATOR; } // Add to the top of the search dirs array_unshift($this->templatePaths, $dir); } } /** * Append content to a given section. * * @param string $section * @param string $content * * @return void */ protected function extendSection($section, $content) { if (isset($this->sections[$section])) { $content = str_replace('@parent', $content, $this->sections[$section]); } $this->sections[$section] = $content; } /** * Evaluates the template described in the _tempFilePath property * * @param array $forceParams Forced parameters * * @return string * @throws Exception */ protected function processTemplate(array &$forceParams) { // If the engine returned raw content, return the raw content immediately if ($this->_tempFilePath['type'] == 'raw') { return $this->_tempFilePath['content']; } if (substr($this->_tempFilePath['content'], 0, 4) == 'raw|') { return substr($this->_tempFilePath['content'], 4); } $obLevel = ob_get_level(); ob_start(); // We'll process the contents of the view inside a try/catch block so we can // flush out any stray output that might get out before an error occurs or // an exception is thrown. This prevents any partial views from leaking. try { $this->includeTemplateFile($forceParams); } catch (Exception $e) { $this->handleViewException($e, $obLevel); } return ob_get_clean(); } /** * Handle a view exception. * * @param Exception $e The exception to handle * @param int $obLevel The target output buffering level * * @return void * * @throws $e */ protected function handleViewException(Exception $e, $obLevel) { while (ob_get_level() > $obLevel) { ob_end_clean(); } $message = $e->getMessage() . ' (View template: ' . realpath($this->_tempFilePath['content']) . ')'; $newException = new ErrorException($message, 0, 1, $e->getFile(), $e->getLine(), $e); throw $newException; } /** * Get the appropriate view engine for the given view template path. * * @param string $path The path of the view template * * @return EngineInterface * * @throws UnrecognisedExtension */ protected function getEngine($path) { foreach ($this->viewEngineMap as $extension => $engine) { if (substr($path, -strlen($extension)) == $extension) { return new $engine($this); } } throw new UnrecognisedExtension($path); } /** * Get the extension used by the view file. * * @param string $path * * @return string */ protected function getExtension($path) { $extensions = array_keys($this->viewEngineMap); return array_first($extensions, function ($key, $value) use ($path) { return ends_with($path, $value); }); } /** * Triggers an object-specific event. The event runs both locally –if a suitable method exists– and through the * Joomla! plugin system. A true/false return value is expected. The first false return cancels the event. * * EXAMPLE * Component: com_foobar, Object name: item, Event: onBeforeSomething, Arguments: array(123, 456) * The event calls: * 1. $this->onBeforeSomething(123, 456) * 2. Joomla! plugin event onComFoobarViewItemBeforeSomething($this, 123, 456) * * @param string $event The name of the event, typically named onPredicateVerb e.g. onBeforeKick * @param array $arguments The arguments to pass to the event handlers * * @return bool */ protected function triggerEvent($event, array $arguments = []) { $result = true; // If there is an object method for this event, call it if (method_exists($this, $event)) { switch (count($arguments)) { case 0: $result = $this->{$event}(); break; case 1: $result = $this->{$event}($arguments[0]); break; case 2: $result = $this->{$event}($arguments[0], $arguments[1]); break; case 3: $result = $this->{$event}($arguments[0], $arguments[1], $arguments[2]); break; case 4: $result = $this->{$event}($arguments[0], $arguments[1], $arguments[2], $arguments[3]); break; case 5: $result = $this->{$event}($arguments[0], $arguments[1], $arguments[2], $arguments[3], $arguments[4]); break; default: $result = call_user_func_array([$this, $event], $arguments); break; } } if ($result === false) { return false; } // All other event handlers live outside this object, therefore they need to be passed a reference to this // objects as the first argument. array_unshift($arguments, $this); // If we have an "on" prefix for the event (e.g. onFooBar) remove it and stash it for later. $prefix = ''; if (substr($event, 0, 2) == 'on') { $prefix = 'on'; $event = substr($event, 2); } // Get the component/model prefix for the event $prefix .= 'Com' . ucfirst($this->container->bareComponentName) . 'View'; $prefix .= ucfirst($this->getName()); // The event name will be something like onComFoobarItemsBeforeSomething $event = $prefix . $event; // Call the Joomla! plugins $results = $this->container->platform->runPlugins($event, $arguments); if (!empty($results)) { foreach ($results as $result) { if ($result === false) { return false; } } } return true; } /** * Runs before rendering the view template, echoing HTML to put before the * view template's generated HTML * * @return void */ protected function preRender() { // You need to implement this in children classes } /** * Runs after rendering the view template, echoing HTML to put after the * view template's generated HTML * * @return void */ protected function postRender() { // You need to implement this in children classes } /** * This method makes sure the current scope isn't polluted with variables when including a view template * * @param array $forceParams Forced parameters * * @return void */ private function includeTemplateFile(array &$forceParams) { // Extract forced parameters if (!empty($forceParams)) { extract($forceParams); } include $this->_tempFilePath['content']; } } PK t!]��BV* * DataView/Csv.phpnu &1i� <?php /** * @package FOF * @copyright Copyright (c)2010-2020 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; } } PK t!]�ut�g'