API Explicitly load project template files after modules

Resolves an issue where if not using the themes directory (i.e just a single app folder) you cannot override module templates.
Changes the SS_TemplateManifest constructor with a new $project argument.
This commit is contained in:
Will Rossiter 2012-11-02 20:28:39 +13:00 committed by Ingo Schommer
parent a108f67476
commit 683db8dc1d
12 changed files with 90 additions and 28 deletions

View File

@ -290,7 +290,7 @@ $configManifest = new SS_ConfigManifest(BASE_PATH, false, $flush);
Config::inst()->pushConfigManifest($configManifest);
SS_TemplateLoader::instance()->pushManifest(new SS_TemplateManifest(
BASE_PATH, false, isset($_GET['flush'])
BASE_PATH, project(), false, isset($_GET['flush'])
));
// If in live mode, ensure deprecation, strict and notices are not reported

View File

@ -49,7 +49,8 @@ class SS_TemplateLoader {
/**
* Attempts to find possible candidate templates from a set of template
* names and a theme.
* names from modules, current theme directory and finally the application
* folder.
*
* The template names can be passed in as plain strings, or be in the
* format "type/name", where type is the type of template to search for
@ -57,10 +58,12 @@ class SS_TemplateLoader {
*
* @param string|array $templates
* @param string $theme
*
* @return array
*/
public function findTemplates($templates, $theme = null) {
$result = array();
$project = project();
foreach ((array) $templates as $template) {
$found = false;
@ -71,21 +74,14 @@ class SS_TemplateLoader {
$type = null;
}
if ($candidates = $this->getManifest()->getTemplate($template)) {
if ($theme && isset($candidates['themes'][$theme])) {
$found = $candidates['themes'][$theme];
} else {
unset($candidates['themes']);
$found = $candidates;
}
if ($found) {
if ($type && isset($found[$type])) {
$found = array('main' => $found[$type]);
}
$result = array_merge($found, $result);
if ($found = $this->getManifest()->getCandidateTemplate($template, $theme)) {
if ($type && isset($found[$type])) {
$found = array(
'main' => $found[$type]
);
}
$result = array_merge($found, $result);
}
}

View File

@ -14,6 +14,7 @@ class SS_TemplateManifest {
protected $tests;
protected $cache;
protected $cacheKey;
protected $project;
protected $inited;
protected $forceRegen;
protected $templates = array();
@ -23,13 +24,17 @@ class SS_TemplateManifest {
* or loaded from cache until needed.
*
* @param string $base The base path.
* @param string $project Path to application code
*
* @param bool $includeTests Include tests in the manifest.
* @param bool $forceRegen Force the manifest to be regenerated.
*/
public function __construct($base, $includeTests = false, $forceRegen = false) {
public function __construct($base, $project, $includeTests = false, $forceRegen = false) {
$this->base = $base;
$this->tests = $includeTests;
$this->project = $project;
$this->cacheKey = $this->tests ? 'manifest_tests' : 'manifest';
$this->forceRegen = $forceRegen;
@ -96,6 +101,30 @@ class SS_TemplateManifest {
}
}
/**
* Returns the correct candidate template. In order of importance, application
* project code, current theme and finally modules.
*
* @param string $name
* @param string $theme - theme name
*
* @return array
*/
public function getCandidateTemplate($name, $theme = null) {
$candidates = $this->getTemplate($name);
if ($this->project && isset($candidates[$this->project])) {
$found = $candidates[$this->project];
} else if ($theme && isset($candidates['themes'][$theme])) {
$found = $candidates['themes'][$theme];
} else {
unset($candidates['themes']);
$found = $candidates;
}
return $found;
}
/**
* Regenerates the manifest by scanning the base path.
*
@ -109,6 +138,7 @@ class SS_TemplateManifest {
'ignore_tests' => !$this->tests,
'file_callback' => array($this, 'handleFile')
));
$finder->find($this->base);
if ($cache) {
@ -119,13 +149,16 @@ class SS_TemplateManifest {
}
public function handleFile($basename, $pathname, $depth) {
$projectFile = false;
$theme = null;
if (strpos($pathname, $this->base . '/' . THEMES_DIR) === 0) {
$start = strlen($this->base . '/' . THEMES_DIR) + 1;
$theme = substr($pathname, $start);
$theme = substr($theme, 0, strpos($theme, '/'));
$theme = strtok($theme, '_');
} else {
$theme = null;
} else if($this->project && (strpos($pathname, $this->base . '/' . $this->project .'/') === 0)) {
$projectFile = true;
}
$type = basename(dirname($pathname));
@ -137,9 +170,12 @@ class SS_TemplateManifest {
if ($theme) {
$this->templates[$name]['themes'][$theme][$type] = $pathname;
} else if($projectFile) {
$this->templates[$name][$this->project][$type] = $pathname;
} else {
$this->templates[$name][$type] = $pathname;
}
}
protected function init() {
@ -150,5 +186,4 @@ class SS_TemplateManifest {
$this->regenerate();
}
}
}

View File

@ -94,7 +94,7 @@ class TestRunner extends Controller {
SapphireTest::set_test_class_manifest($classManifest);
SS_TemplateLoader::instance()->pushManifest(new SS_TemplateManifest(
BASE_PATH, true, isset($_GET['flush'])
BASE_PATH, project(), true, isset($_GET['flush'])
));
}

View File

@ -9,7 +9,7 @@ class TemplateLoaderTest extends SapphireTest {
public function testFindTemplates() {
$base = dirname(__FILE__) . '/fixtures/templatemanifest';
$manifest = new SS_TemplateManifest($base, false, true);
$manifest = new SS_TemplateManifest($base, 'myproject', false, true);
$loader = new SS_TemplateLoader();
$manifest->regenerate(false);
@ -40,7 +40,23 @@ class TemplateLoaderTest extends SapphireTest {
'main' => "$base/module/templates/Page.ss",
'Layout' => "$base/module/templates/Layout/CustomPage.ss"
);
$this->assertEquals($expectCustomPage, $loader->findTemplates(array('CustomPage', 'Page')));
}
public function testFindTemplatesApplicationOverridesModule() {
$base = dirname(__FILE__) . '/fixtures/templatemanifest';
$manifest = new SS_TemplateManifest($base, 'myproject', false, true);
$loader = new SS_TemplateLoader();
$manifest->regenerate(false);
$loader->pushManifest($manifest);
$expectPage = array(
'main' => "$base/myproject/templates/CustomTemplate.ss"
);
$this->assertEquals($expectPage, $loader->findTemplates('CustomTemplate'));
}
}

View File

@ -15,8 +15,8 @@ class TemplateManifestTest extends SapphireTest {
parent::setUp();
$this->base = dirname(__FILE__) . '/fixtures/templatemanifest';
$this->manifest = new SS_TemplateManifest($this->base);
$this->manifestTests = new SS_TemplateManifest($this->base, true);
$this->manifest = new SS_TemplateManifest($this->base, 'myproject');
$this->manifestTests = new SS_TemplateManifest($this->base, 'myproject', true);
$this->manifest->regenerate(false);
$this->manifestTests->regenerate(false);
@ -38,6 +38,12 @@ class TemplateManifestTest extends SapphireTest {
'custompage' => array(
'Layout' => "{$this->base}/module/templates/Layout/CustomPage.ss"
),
'customtemplate' => array(
'main' => "{$this->base}/module/templates/CustomTemplate.ss",
'myproject' => array(
'main' => "{$this->base}/myproject/templates/CustomTemplate.ss"
)
),
'subfolder' => array(
'main' => "{$this->base}/module/subfolder/templates/Subfolder.ss"
),
@ -93,6 +99,12 @@ class TemplateManifestTest extends SapphireTest {
$this->assertEquals(array(), $this->manifest->getTemplate('Test'));
$this->assertEquals($expectTests, $this->manifestTests->getTemplate('Test'));
$this->assertEquals(array(
'main' => "{$this->base}/module/templates/CustomTemplate.ss",
'myproject' => array(
'main' => "{$this->base}/myproject/templates/CustomTemplate.ss"
)), $this->manifestTests->getTemplate('CustomTemplate'));
}
}

View File

@ -0,0 +1 @@
Custom Template

View File

@ -0,0 +1 @@
<?php

View File

@ -15,13 +15,13 @@ class i18nSSLegacyAdapterTest extends SapphireTest {
Director::setBaseFolder($this->alternateBasePath);
// Push a template loader running from the fake webroot onto the stack.
$templateManifest = new SS_TemplateManifest($this->alternateBasePath, false, true);
$templateManifest = new SS_TemplateManifest($this->alternateBasePath, null, false, true);
$templateManifest->regenerate(false);
SS_TemplateLoader::instance()->pushManifest($templateManifest);
$this->_oldTheme = SSViewer::current_theme();
SSViewer::set_theme('testtheme1');
$classManifest = new SS_ClassManifest($this->alternateBasePath, true, true, false);
$classManifest = new SS_ClassManifest($this->alternateBasePath, null, true, true, false);
SS_ClassLoader::instance()->pushManifest($classManifest);
$this->originalLocale = i18n::get_locale();

View File

@ -34,7 +34,7 @@ class i18nTest extends SapphireTest {
Director::setBaseFolder($this->alternateBasePath);
// Push a template loader running from the fake webroot onto the stack.
$templateManifest = new SS_TemplateManifest($this->alternateBasePath, false, true);
$templateManifest = new SS_TemplateManifest($this->alternateBasePath, null, false, true);
$templateManifest->regenerate(false);
SS_TemplateLoader::instance()->pushManifest($templateManifest);
$this->_oldTheme = SSViewer::current_theme();

View File

@ -33,7 +33,7 @@ class i18nTextCollectorTest extends SapphireTest {
$this->alternateBasePath, false, true, false
);
$manifest = new SS_TemplateManifest($this->alternateBasePath, false, true);
$manifest = new SS_TemplateManifest($this->alternateBasePath, null, false, true);
$manifest->regenerate(false);
SS_TemplateLoader::instance()->pushManifest($manifest);
}