-
Notifications
You must be signed in to change notification settings - Fork 179
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #270 from thephpleague/themes
Themes Support #234
- Loading branch information
Showing
13 changed files
with
422 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
+++ | ||
title = "Themes" | ||
linkTitle = "Engine Themes" | ||
[menu.main] | ||
parent = "engine" | ||
weight = 6 | ||
[menu.main.params] | ||
badge = "v3.5" | ||
+++ | ||
|
||
Themes provide an alternative to template path resolution that allow for a holistic approach to template overrides and fallbacks. | ||
|
||
## Usage | ||
|
||
Given an engine configuration like: | ||
|
||
```php | ||
use League\Plates\{Engine, Template\Theme}; | ||
|
||
$plates = Engine::fromTheme(Theme::hierarchy([ | ||
Theme::new('/templates/main', 'Main'), // parent | ||
Theme::new('/templates/user', 'User'), // child | ||
Theme::new('/templates/seasonal', 'Seasonal'), // child2 | ||
])); | ||
``` | ||
|
||
And a file structure like: | ||
|
||
``` | ||
templates/ | ||
main/ | ||
layout.php | ||
home.php | ||
header.php | ||
user/ | ||
layout.php | ||
header.php | ||
seasonal/ | ||
header.php | ||
``` | ||
|
||
The following looks ups, *regardless of where they are called from*, would resolve to the following files: | ||
|
||
```php | ||
$templates->render('home'); // templates/main/home.php | ||
$templates->render('layout'); // templates/user/layout.php | ||
$templates->render('header'); // templates/seasonal/header.php | ||
``` | ||
|
||
All paths are resolved from the last child to the first parent allowing a hierarchy of overrides. | ||
|
||
## Differences from Directory and Folders | ||
|
||
This logic is used **instead of** the directories and folders feature since they are distinct in nature, and combining the logic isn't obvious on how the features should stack. | ||
|
||
Creating an engine with one theme is functionally equivalent to using just a directory with no folders. | ||
|
||
The fallback functionality is a bit different however since with folders, it's *opt in*, you need to prefix the template name with the folder name. With themes, all template names implicitly will be resolved and fallback according to the hierarchy setup. | ||
|
||
## Additional Customization | ||
|
||
This functionality is powered by the `League\Plates\Template\ResolveTemplatePath` interface. If you'd prefer a more complex or specific path resolution, you can just implement your own and assign it to the engine instance with: | ||
|
||
```php | ||
$plates = Engine::withResolveTemplatePath(new MyCustomResolveTemplatePath()); | ||
``` | ||
|
||
The resolve template path should always resolve a string that represents a verified path on the filesystem or throw a TemplateNotFound exception. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -21,3 +21,7 @@ | |
.version-select { | ||
margin: 8px 25px 0px 45px; | ||
} | ||
|
||
.menu-badge { | ||
color: #ff4143; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
<?php | ||
|
||
namespace League\Plates\Exception; | ||
|
||
final class TemplateNotFound extends \LogicException | ||
{ | ||
private $template; | ||
private $paths; | ||
|
||
public function __construct(string $template, array $paths, string $message) { | ||
$this->template = $template; | ||
$this->paths = $paths; | ||
parent::__construct($message); | ||
} | ||
|
||
public function template(): string { | ||
return $this->template; | ||
} | ||
|
||
public function paths(): array { | ||
return $this->paths; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
<?php | ||
|
||
namespace League\Plates\Template; | ||
|
||
use League\Plates\Exception\TemplateNotFound; | ||
|
||
interface ResolveTemplatePath | ||
{ | ||
/** | ||
* @throws TemplateNotFound if the template could not be properly resolved to a file path | ||
*/ | ||
public function __invoke(Name $name): string; | ||
} |
20 changes: 20 additions & 0 deletions
20
src/Template/ResolveTemplatePath/NameAndFolderResolveTemplatePath.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
<?php | ||
|
||
namespace League\Plates\Template\ResolveTemplatePath; | ||
|
||
use League\Plates\Exception\TemplateNotFound; | ||
use League\Plates\Template\Name; | ||
use League\Plates\Template\ResolveTemplatePath; | ||
|
||
/** Resolves the path from the logic in the Name class which resolves via folder lookup, and then the default directory */ | ||
final class NameAndFolderResolveTemplatePath implements ResolveTemplatePath | ||
{ | ||
public function __invoke(Name $name): string { | ||
$path = $name->getPath(); | ||
if (is_file($path)) { | ||
return $path; | ||
} | ||
|
||
throw new TemplateNotFound($name->getName(), [$name->getPath()], 'The template "' . $name->getName() . '" could not be found at "' . $name->getPath() . '".'); | ||
} | ||
} |
41 changes: 41 additions & 0 deletions
41
src/Template/ResolveTemplatePath/ThemeResolveTemplatePath.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
<?php | ||
|
||
namespace League\Plates\Template\ResolveTemplatePath; | ||
|
||
use League\Plates\Exception\TemplateNotFound; | ||
use League\Plates\Template\Name; | ||
use League\Plates\Template\ResolveTemplatePath; | ||
use League\Plates\Template\Theme; | ||
|
||
final class ThemeResolveTemplatePath implements ResolveTemplatePath | ||
{ | ||
private $theme; | ||
|
||
public function __construct(Theme $theme) { | ||
$this->theme = $theme; | ||
} | ||
|
||
public function __invoke(Name $name): string { | ||
$searchedPaths = []; | ||
foreach ($this->theme->listThemeHierarchy() as $theme) { | ||
$path = $theme->dir() . '/' . $name->getName() . '.' . $name->getEngine()->getFileExtension(); | ||
if (is_file($path)) { | ||
return $path; | ||
} | ||
$searchedPaths[] = [$theme->name(), $path]; | ||
} | ||
|
||
throw new TemplateNotFound( | ||
$name->getName(), | ||
array_map(function(array $tup) { | ||
return $tup[1]; | ||
}, $searchedPaths), | ||
sprintf('The template "%s" was not found in the following themes: %s', | ||
$name->getName(), | ||
implode(', ', array_map(function(array $tup) { | ||
return implode(':', $tup); | ||
}, $searchedPaths)) | ||
) | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.