Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[5.3] Allow adding additional layout base path to form fields #44590

Open
wants to merge 9 commits into
base: 5.3-dev
Choose a base branch
from
72 changes: 69 additions & 3 deletions libraries/src/Form/FormField.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
use Joomla\Database\DatabaseAwareTrait;
use Joomla\Database\DatabaseInterface;
use Joomla\Database\Exception\DatabaseNotFoundException;
use Joomla\Filesystem\Path;
use Joomla\Registry\Registry;
use Joomla\String\Normalise;
use Joomla\String\StringHelper;
Expand Down Expand Up @@ -398,6 +399,14 @@ abstract class FormField implements DatabaseAwareInterface, CurrentUserInterface
*/
protected $renderLabelLayout = 'joomla.form.renderlabel';

/**
* Additional layout paths to look for layout files
*
* @var array
* @since __DEPLOY_VERSION__
*/
protected $layoutPaths = [];

/**
* The data-attribute name and values of the form field.
* For example, data-action-type="click" data-action-type="change"
Expand Down Expand Up @@ -591,6 +600,25 @@ public function __set($name, $value)
$this->$name = (int) $value;
break;

case 'layoutIncludePath':
$app = Factory::getApplication();

if ($app->isClient('site') || $app->isClient('administrator')) {
// Try to get a default template
$template = $app->getTemplate(true);

// Use unshift to use a lower priority
array_unshift($this->layoutPaths, JPATH_THEMES . '/' . $template->template . '/html/' . ltrim((string) $value, '/'));

if (!empty($template->parent)) {
array_unshift($this->layoutPaths, JPATH_THEMES . '/' . $template->parent . '/html/' . ltrim((string) $value, '/'));
}
}

// Use unshift to use a lower priority
array_unshift($this->layoutPaths, JPATH_ROOT . '/' . ltrim((string) $value, '/'));
break;

default:
// Detect data attribute(s)
if (strpos($name, 'data-') === 0) {
Expand Down Expand Up @@ -658,7 +686,7 @@ public function setup(\SimpleXMLElement $element, $value, $group = null)
$attributes = [
'multiple', 'name', 'id', 'hint', 'class', 'description', 'labelclass', 'onchange', 'onclick', 'validate', 'pattern', 'validationtext',
'default', 'required', 'disabled', 'readonly', 'autofocus', 'hidden', 'autocomplete', 'spellcheck', 'translateHint', 'translateLabel',
'translate_label', 'translateDescription', 'translate_description', 'size', 'showon', ];
'translate_label', 'translateDescription', 'translate_description', 'size', 'showon', 'layoutIncludePath'];

$this->default = isset($element['value']) ? (string) $element['value'] : $this->default;

Expand Down Expand Up @@ -1060,7 +1088,13 @@ public function renderField($options = [])

$data = array_merge($this->collectLayoutData(), $data);

return $this->getRenderer($this->renderLayout)->render($data);
$renderer = $this->getRenderer($this->renderLayout);

if (isset($options['layoutIncludePath']) && is_dir(Path::check($options['layoutIncludePath']))) {
$renderer->addIncludePaths($options['layoutIncludePath']);
}

return $renderer->render($data);
}

/**
Expand Down Expand Up @@ -1361,6 +1395,32 @@ protected function collectLayoutData(): array
return $this->layoutData;
}

/**
* Add an additional layout path where the renderer should look for layouts.
* Last path added will have highest priority.
*
* @param string $path The path to a layout folder
*
* @return boolean true on success otherwise false
*
* @since __DEPLOY_VERSION__
*/
public function addLayoutPath(string $path): bool
{
// Try to add absolute path
if (!is_dir($path)) {
$path = JPATH_ROOT . '/' . ltrim($path, '/');
}

if (is_dir($path)) {
$this->layoutPaths[] = $path;

return true;
}

return false;
}

/**
* Allow to override renderer include paths in child fields
*
Expand All @@ -1372,7 +1432,13 @@ protected function getLayoutPaths()
{
$renderer = new FileLayout('default');

return $renderer->getDefaultIncludePaths();
$paths = $renderer->getDefaultIncludePaths();

foreach ($this->layoutPaths as $path) {
array_unshift($paths, $path);
}

return $paths;
}

/**
Expand Down