julienmonnerie/kirby/src/Template/Template.php

209 lines
4.5 KiB
PHP
Raw Normal View History

2022-06-17 17:51:59 +02:00
<?php
2023-04-14 16:34:06 +02:00
namespace Kirby\Template;
2022-06-17 17:51:59 +02:00
use Exception;
2023-04-14 16:34:06 +02:00
use Kirby\Cms\App;
2022-06-17 17:51:59 +02:00
use Kirby\Filesystem\F;
use Kirby\Toolkit\Tpl;
/**
* Represents a Kirby template and takes care
* of loading the correct file.
*
2023-04-14 16:34:06 +02:00
* @package Kirby Template
2022-06-17 17:51:59 +02:00
* @author Bastian Allgeier <bastian@getkirby.com>
* @link https://getkirby.com
* @copyright Bastian Allgeier
* @license https://getkirby.com/license
*/
class Template
{
2022-08-31 15:02:43 +02:00
/**
* Global template data
*/
2023-04-14 16:34:06 +02:00
public static array $data = [];
2022-08-31 15:02:43 +02:00
/**
2023-04-14 16:34:06 +02:00
* Default template type if no specific type is set
2022-08-31 15:02:43 +02:00
*/
2023-04-14 16:34:06 +02:00
protected string $defaultType;
2022-08-31 15:02:43 +02:00
/**
2023-04-14 16:34:06 +02:00
* The name of the template
2022-08-31 15:02:43 +02:00
*/
2023-04-14 16:34:06 +02:00
protected string $name;
2022-08-31 15:02:43 +02:00
/**
2023-04-14 16:34:06 +02:00
* Template type (html, json, etc.)
2022-08-31 15:02:43 +02:00
*/
2023-04-14 16:34:06 +02:00
protected string $type;
2022-08-31 15:02:43 +02:00
/**
* Creates a new template object
*/
public function __construct(string $name, string $type = 'html', string $defaultType = 'html')
{
$this->name = strtolower($name);
$this->type = $type;
$this->defaultType = $defaultType;
}
/**
* Converts the object to a simple string
* This is used in template filters for example
*/
public function __toString(): string
{
return $this->name;
}
2023-04-14 16:34:06 +02:00
/**
* Returns the default template type
*/
public function defaultType(): string
{
return $this->defaultType;
}
2022-08-31 15:02:43 +02:00
/**
* Checks if the template exists
*/
public function exists(): bool
{
if ($file = $this->file()) {
return file_exists($file);
}
return false;
}
/**
* Returns the expected template file extension
*/
public function extension(): string
{
return 'php';
}
/**
* Detects the location of the template file
* if it exists.
*/
2022-12-19 14:56:05 +01:00
public function file(): string|null
2022-08-31 15:02:43 +02:00
{
2023-04-14 16:34:06 +02:00
$name = $this->name();
$extension = $this->extension();
$store = $this->store();
$root = $this->root();
2022-08-31 15:02:43 +02:00
if ($this->hasDefaultType() === true) {
try {
// Try the default template in the default template directory.
2023-04-14 16:34:06 +02:00
return F::realpath($root . '/' . $name . '.' . $extension, $root);
2022-12-19 14:56:05 +01:00
} catch (Exception) {
2022-08-31 15:02:43 +02:00
// ignore errors, continue searching
}
// Look for the default template provided by an extension.
2023-04-14 16:34:06 +02:00
$path = App::instance()->extension($store, $name);
2022-08-31 15:02:43 +02:00
if ($path !== null) {
return $path;
}
}
2023-04-14 16:34:06 +02:00
$name .= '.' . $this->type();
2022-08-31 15:02:43 +02:00
try {
// Try the template with type extension in the default template directory.
2023-04-14 16:34:06 +02:00
return F::realpath($root . '/' . $name . '.' . $extension, $root);
2022-12-19 14:56:05 +01:00
} catch (Exception) {
2022-08-31 15:02:43 +02:00
// Look for the template with type extension provided by an extension.
// This might be null if the template does not exist.
2023-04-14 16:34:06 +02:00
return App::instance()->extension($store, $name);
2022-08-31 15:02:43 +02:00
}
}
2023-04-14 16:34:06 +02:00
/**
* Checks if the template uses the default type
*/
public function hasDefaultType(): bool
{
return $this->type() === $this->defaultType();
}
2022-08-31 15:02:43 +02:00
/**
* Returns the template name
*/
public function name(): string
{
return $this->name;
}
/**
2023-04-14 16:34:06 +02:00
* Renders the template with the given template data
2022-08-31 15:02:43 +02:00
*/
public function render(array $data = []): string
{
2023-04-14 16:34:06 +02:00
// if the template is rendered inside a snippet,
// we need to keep the "outside" snippet object
// to compare it later
$snippet = Snippet::$current;
// load the template
$template = Tpl::load($this->file(), $data);
// if last `endsnippet()` inside the current template
// has been omitted (= snippet was used as layout snippet),
// `Snippet::$current` will point to a snippet that was
// opened inside the template; if that snippet is the direct
// child of the snippet that was open before the template was
// rendered (which could be `null` if no snippet was open),
// take the buffer output from the template as default slot
// and render the snippet as final template output
if (
Snippet::$current === null ||
Snippet::$current->parent() !== $snippet
) {
return $template;
}
// no slots have been defined, but the template code
// should be used as default slot
if (Snippet::$current->slots()->count() === 0) {
return Snippet::$current->render($data, [
'default' => $template
]);
}
// let the snippet close and render natively
return Snippet::$current->render($data);
2022-08-31 15:02:43 +02:00
}
/**
* Returns the root to the templates directory
*/
public function root(): string
{
return App::instance()->root($this->store());
}
/**
2023-04-14 16:34:06 +02:00
* Returns the place where templates are located
* in the site folder and and can be found in extensions
2022-08-31 15:02:43 +02:00
*/
2023-04-14 16:34:06 +02:00
public function store(): string
2022-08-31 15:02:43 +02:00
{
2023-04-14 16:34:06 +02:00
return 'templates';
2022-08-31 15:02:43 +02:00
}
/**
2023-04-14 16:34:06 +02:00
* Returns the template type
2022-08-31 15:02:43 +02:00
*/
2023-04-14 16:34:06 +02:00
public function type(): string
2022-08-31 15:02:43 +02:00
{
2023-04-14 16:34:06 +02:00
return $this->type;
2022-08-31 15:02:43 +02:00
}
2022-06-17 17:51:59 +02:00
}