Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions CHANGELOG-WIP.md
Original file line number Diff line number Diff line change
Expand Up @@ -767,6 +767,16 @@ Moved the following controllers:
- Deprecated `craft\services\Tokens`. `CraftCms\Cms\RouteToken\RouteTokens` should be used instead.
- Deprecated `craft\records\Token`. `CraftCms\Cms\RouteToken\Models\RouteToken` should be used instead.

## Twig

- Added `CraftCms\Cms\Twig\TemplateResolver`.
- Added `CraftCms\Cms\Twig\TemplateLoader`.
- Added `CraftCms\Cms\Twig\Exceptions\TemplateLoaderException`.
- Deprecated `craft\web\View::doesTemplateExist()`. `CraftCms\Cms\Twig\TemplateResolver::doesTemplateExist()` should be used instead.
- Deprecated `craft\web\View::resolveTemplate()`. `CraftCms\Cms\Twig\TemplateResolver::resolveTemplate()` should be used instead.
- Deprecated `craft\web\twig\TemplateLoader`. `CraftCms\Cms\Twig\TemplateLoader` should be used instead.
- Deprecated `craft\web\twig\TemplateLoaderException`. `CraftCms\Cms\Twig\Exceptions\TemplateLoaderException` should be used instead.

## Translations

- Deprecated `craft\i18n\FormatConverter`. `CraftCms\Cms\Translation\FormatConverter` should be used instead.
Expand Down Expand Up @@ -810,6 +820,7 @@ Moved the following controllers:

## View

- Added `CraftCms\Cms\View\TwigEngine`.
- Added `CraftCms\Cms\View\AssetRegistry`.
- Added `CraftCms\Cms\Support\Facades\AssetRegistry`.
- Added `CraftCms\Cms\View\Enums\Position` enum.
Expand Down
3 changes: 1 addition & 2 deletions src/Console/Commands/Twig/TwigCacheCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,8 @@
namespace CraftCms\Cms\Console\Commands\Twig;

use Craft;
use craft\web\twig\TemplateLoaderException;
use craft\web\View;
use CraftCms\Cms\Console\CraftCommand;
use CraftCms\Cms\Twig\Exceptions\TemplateLoaderException;
use CraftCms\Cms\View\TemplateMode;
use Illuminate\Console\Command;
use Illuminate\Support\Collection;
Expand Down
3 changes: 2 additions & 1 deletion src/Deprecator/Deprecator.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
use CraftCms\Cms\Deprecator\Models\DeprecationError;
use CraftCms\Cms\Support\Arr;
use CraftCms\Cms\Support\Str;
use CraftCms\Cms\Twig\TemplateResolver;
use Illuminate\Container\Attributes\Singleton;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
Expand Down Expand Up @@ -204,7 +205,7 @@ private function findOrigin(array $traces): array

if ($template instanceof TwigTemplate) {
$templateName = $template->getTemplateName();
$file = Craft::$app->getView()->resolveTemplate($templateName) ?: $templateName;
$file = app(TemplateResolver::class)->resolve($templateName) ?: $templateName;
$line = $this->findTemplateLine($template, $templateCodeLine);

return [$file, $line];
Expand Down
3 changes: 2 additions & 1 deletion src/Element/Concerns/Renderable.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use CraftCms\Cms\Element\Events\Render;
use CraftCms\Cms\Support\Arr;
use CraftCms\Cms\Support\Html;
use CraftCms\Cms\Twig\TemplateResolver;
use CraftCms\Cms\View\TemplateMode;
use Twig\Markup;

Expand Down Expand Up @@ -46,7 +47,7 @@ public function render(array $variables = []): Markup
if (! empty($templates)) {
$view = Craft::$app->getView();
foreach (Arr::sort($templates, 'priority') as $template) {
if (! $view->doesTemplateExist($template['template'], TemplateMode::Site->value)) {
if (! app(TemplateResolver::class)->exists($template['template'], TemplateMode::Site)) {
continue;
}

Expand Down
3 changes: 2 additions & 1 deletion src/Http/Controllers/Users/PhotoController.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use craft\helpers\Assets;
use CraftCms\Cms\Asset\Elements\Asset;
use CraftCms\Cms\Http\RespondsWithFlash;
use CraftCms\Cms\Twig\TemplateResolver;
use CraftCms\Cms\User\Elements\User;
use CraftCms\Cms\User\Users;
use CraftCms\Cms\View\TemplateMode;
Expand Down Expand Up @@ -109,7 +110,7 @@ private function renderPhotoTemplate(Request $request, User $user): JsonResponse
$view = Craft::$app->getView();

$templateMode = TemplateMode::get();
if (TemplateMode::is(TemplateMode::Site) && ! $view->doesTemplateExist('users/_photo.twig')) {
if (TemplateMode::is(TemplateMode::Site) && ! app(TemplateResolver::class)->exists('users/_photo.twig')) {
$templateMode = TemplateMode::Cp;
}

Expand Down
17 changes: 17 additions & 0 deletions src/Twig/Exceptions/TemplateLoaderException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

declare(strict_types=1);

namespace CraftCms\Cms\Twig\Exceptions;

use Twig\Error\LoaderError;

class TemplateLoaderException extends LoaderError
{
public function __construct(
public string $template,
string $message
) {
parent::__construct($message);
}
}
90 changes: 90 additions & 0 deletions src/Twig/TemplateLoader.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
<?php

declare(strict_types=1);

namespace CraftCms\Cms\Twig;

use CraftCms\Cms\Twig\Exceptions\TemplateLoaderException;
use CraftCms\Cms\Updates\Updates;
use Twig\Loader\LoaderInterface;
use Twig\Source;

use function CraftCms\Cms\t;

final readonly class TemplateLoader implements LoaderInterface
{
public function __construct(
private TemplateResolver $resolver,
) {}

/**
* {@inheritdoc}
*/
public function exists(string $name): bool
{
return $this->resolver->exists($name);
}

/**
* {@inheritdoc}
*/
public function getSourceContext(string $name): Source
{
$template = $this->resolveTemplate($name);

if (! is_readable($template)) {
throw new TemplateLoaderException($name, t('Tried to read the template at {path}, but could not. Check the permissions.', ['path' => $template]));
}

return new Source(file_get_contents($template), $name, $template);
}

/**
* Gets the cache key to use for the cache for a given template.
*
* @param string $name The name of the template to load
* @return string The cache key (the path to the template)
*
* @throws TemplateLoaderException if the template doesn’t exist
*/
public function getCacheKey(string $name): string
{
return $this->resolveTemplate($name);
}

/**
* Returns whether the cached template is still up to date with the latest template.
*
* @param string $name The template name
* @param int $time The last modification time of the cached template
*
* @throws TemplateLoaderException if the template doesn’t exist
*/
public function isFresh(string $name, int $time): bool
{
// If this is a control panel request and a DB update is needed, force a recompile.
if (request()->isCpRequest() && app(Updates::class)->isCraftUpdatePending()) {
return false;
}

$sourceModifiedTime = filemtime($this->resolveTemplate($name));

return $sourceModifiedTime <= $time;
}

/**
* Returns the path to a given template, or throws a TemplateLoaderException.
*
* @throws TemplateLoaderException if the template doesn’t exist
*/
private function resolveTemplate(string $name): string
{
$template = $this->resolver->resolve($name);

if ($template !== false) {
return $template;
}

throw new TemplateLoaderException($name, t('Unable to find the template “{template}”.', ['template' => $name]));
}
}
Loading
Loading