mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
API: Look for templates of namespaced classes in subfolders.
This change will mean that SilverStripe\Control\Controller will look for its template in templates/SilverStripe/Control/Controller.ss. In order to preserve some backwards campatibility, non-namespaced classes can have the templates stored in any template subfolder, but once you add a namespace to a class, the namespaced path expression will need to be a subfolder of <module>/templates or themes/<theme>/templates. Layout and Content templates are stil supported as special template type, Includes still functions but is a no-op. Other template subfolders should not be used.
This commit is contained in:
parent
d44fe5311d
commit
65eb0bde6a
@ -178,34 +178,86 @@ class SS_TemplateManifest {
|
|||||||
$this->inited = true;
|
$this->inited = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function handleFile($basename, $pathname, $depth) {
|
public function handleFile($basename, $pathname, $depth)
|
||||||
|
{
|
||||||
$projectFile = false;
|
$projectFile = false;
|
||||||
$theme = null;
|
$theme = null;
|
||||||
|
|
||||||
if (strpos($pathname, $this->base . '/' . THEMES_DIR) === 0) {
|
// Template in theme
|
||||||
$start = strlen($this->base . '/' . THEMES_DIR) + 1;
|
if (preg_match(
|
||||||
$theme = substr($pathname, $start);
|
'#'.preg_quote($this->base.'/'.THEMES_DIR).'/([^/_]+)(_[^/]+)?/(.*)$#',
|
||||||
$theme = substr($theme, 0, strpos($theme, '/'));
|
$pathname,
|
||||||
$theme = strtok($theme, '_');
|
$matches
|
||||||
} else if($this->project && (strpos($pathname, $this->base . '/' . $this->project .'/') === 0)) {
|
)) {
|
||||||
|
$theme = $matches[1];
|
||||||
|
$relPath = $matches[3];
|
||||||
|
|
||||||
|
// Template in project
|
||||||
|
} elseif (preg_match(
|
||||||
|
'#'.preg_quote($this->base.'/'.$this->project).'/(.*)$#',
|
||||||
|
$pathname,
|
||||||
|
$matches
|
||||||
|
)) {
|
||||||
$projectFile = true;
|
$projectFile = true;
|
||||||
|
$relPath = $matches[1];
|
||||||
|
|
||||||
|
// Template in module
|
||||||
|
} elseif (preg_match(
|
||||||
|
'#'.preg_quote($this->base).'/([^/]+)/(.*)$#',
|
||||||
|
$pathname,
|
||||||
|
$matches
|
||||||
|
)) {
|
||||||
|
$relPath = $matches[2];
|
||||||
|
|
||||||
|
} else {
|
||||||
|
throw new \LogicException("Can't determine meaning of path: $pathname");
|
||||||
}
|
}
|
||||||
|
|
||||||
$type = basename(dirname($pathname));
|
// If a templates subfolder is used, ignore that
|
||||||
$name = strtolower(substr($basename, 0, -3));
|
if (preg_match('#'.preg_quote(self::TEMPLATES_DIR).'/(.*)$#', $relPath, $matches)) {
|
||||||
|
$relPath = $matches[1];
|
||||||
if ($type == self::TEMPLATES_DIR) {
|
|
||||||
$type = 'main';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Layout and Content folders have special meaning
|
||||||
|
if (preg_match('#^(.*/)?(Layout|Content|Includes)/([^/]+)$#', $relPath, $matches)) {
|
||||||
|
$type = $matches[2];
|
||||||
|
$relPath = "$matches[1]$matches[3]";
|
||||||
|
} else {
|
||||||
|
$type = "main";
|
||||||
|
}
|
||||||
|
|
||||||
|
$name = strtolower(substr($relPath, 0, -3));
|
||||||
|
$name = str_replace('/', '\\', $name);
|
||||||
|
|
||||||
if ($theme) {
|
if ($theme) {
|
||||||
$this->templates[$name]['themes'][$theme][$type] = $pathname;
|
$this->templates[$name]['themes'][$theme][$type] = $pathname;
|
||||||
} else if($projectFile) {
|
} else if ($projectFile) {
|
||||||
$this->templates[$name][$this->project][$type] = $pathname;
|
$this->templates[$name][$this->project][$type] = $pathname;
|
||||||
} else {
|
} else {
|
||||||
$this->templates[$name][$type] = $pathname;
|
$this->templates[$name][$type] = $pathname;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we've found a template in a subdirectory, then allow its use for a non-namespaced class
|
||||||
|
// as well. This was a common SilverStripe 3 approach, where templates were placed into
|
||||||
|
// subfolders to suit the whim of the developer.
|
||||||
|
if (strpos($name, '\\') !== false) {
|
||||||
|
$name2 = substr($name, strrpos($name, '\\') + 1);
|
||||||
|
// In of these cases, the template will only be provided if it isn't already set. This
|
||||||
|
// matches SilverStripe 3 prioritisation.
|
||||||
|
if ($theme) {
|
||||||
|
if (!isset($this->templates[$name2]['themes'][$theme][$type])) {
|
||||||
|
$this->templates[$name2]['themes'][$theme][$type] = $pathname;
|
||||||
|
}
|
||||||
|
} else if ($projectFile) {
|
||||||
|
if (!isset($this->templates[$name2][$this->project][$type])) {
|
||||||
|
$this->templates[$name2][$this->project][$type] = $pathname;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!isset($this->templates[$name2][$type])) {
|
||||||
|
$this->templates[$name2][$type] = $pathname;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function init() {
|
protected function init() {
|
||||||
|
@ -25,7 +25,7 @@ class TemplateManifestTest extends SapphireTest {
|
|||||||
public function testGetTemplates() {
|
public function testGetTemplates() {
|
||||||
$expect = array(
|
$expect = array(
|
||||||
'root' => array(
|
'root' => array(
|
||||||
'module' => "{$this->base}/module/Root.ss"
|
'main' => "{$this->base}/module/Root.ss"
|
||||||
),
|
),
|
||||||
'page' => array(
|
'page' => array(
|
||||||
'main' => "{$this->base}/module/templates/Page.ss",
|
'main' => "{$this->base}/module/templates/Page.ss",
|
||||||
@ -54,6 +54,30 @@ class TemplateManifestTest extends SapphireTest {
|
|||||||
'theme' => array('main' => "{$this->base}/themes/theme/templates/CustomThemePage.ss",)
|
'theme' => array('main' => "{$this->base}/themes/theme/templates/CustomThemePage.ss",)
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
'mynamespace\myclass' => array(
|
||||||
|
'main' => "{$this->base}/module/templates/MyNamespace/MyClass.ss",
|
||||||
|
'Layout' => "{$this->base}/module/templates/MyNamespace/Layout/MyClass.ss",
|
||||||
|
'themes' => array(
|
||||||
|
'theme' => array(
|
||||||
|
'main' => "{$this->base}/themes/theme/templates/MyNamespace/MyClass.ss",
|
||||||
|
)
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'mynamespace\mysubnamespace\mysubclass' => array(
|
||||||
|
'main' => "{$this->base}/module/templates/MyNamespace/MySubnamespace/MySubclass.ss",
|
||||||
|
),
|
||||||
|
'myclass' => array(
|
||||||
|
'main' => "{$this->base}/module/templates/MyNamespace/MyClass.ss",
|
||||||
|
'Layout' => "{$this->base}/module/templates/MyNamespace/Layout/MyClass.ss",
|
||||||
|
'themes' => array(
|
||||||
|
'theme' => array(
|
||||||
|
'main' => "{$this->base}/themes/theme/templates/MyNamespace/MyClass.ss",
|
||||||
|
)
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'mysubclass' => array(
|
||||||
|
'main' => "{$this->base}/module/templates/MyNamespace/MySubnamespace/MySubclass.ss",
|
||||||
|
),
|
||||||
'include' => array('themes' => array(
|
'include' => array('themes' => array(
|
||||||
'theme' => array(
|
'theme' => array(
|
||||||
'Includes' => "{$this->base}/themes/theme/templates/Includes/Include.ss"
|
'Includes' => "{$this->base}/themes/theme/templates/Includes/Include.ss"
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
MyClass.ss
|
@ -0,0 +1 @@
|
|||||||
|
MyClass.ss
|
@ -0,0 +1 @@
|
|||||||
|
MySubclass.ss
|
@ -1124,24 +1124,24 @@ after')
|
|||||||
$self = $this;
|
$self = $this;
|
||||||
$this->useTestTheme(dirname(__FILE__), 'layouttest', function() use ($self) {
|
$this->useTestTheme(dirname(__FILE__), 'layouttest', function() use ($self) {
|
||||||
// Test passing a string
|
// Test passing a string
|
||||||
$templates = SSViewer::get_templates_by_class('SSViewerTest_Controller', '', 'Controller');
|
$templates = SSViewer::get_templates_by_class(
|
||||||
$self->assertCount(2, $templates);
|
'TestNamespace\SSViewerTest_Controller',
|
||||||
|
'',
|
||||||
|
'Controller'
|
||||||
|
);
|
||||||
|
$self->assertEquals([
|
||||||
|
'TestNamespace\SSViewerTest_Controller',
|
||||||
|
'Controller',
|
||||||
|
], $templates);
|
||||||
|
|
||||||
// Test to ensure we're stopping at the base class.
|
// Test to ensure we're stopping at the base class.
|
||||||
$templates = SSViewer::get_templates_by_class('SSViewerTest_Controller', '', 'SSViewerTest_Controller');
|
$templates = SSViewer::get_templates_by_class('TestNamespace\SSViewerTest_Controller', '', 'TestNamespace\SSViewerTest_Controller');
|
||||||
$self->assertCount(1, $templates);
|
$self->assertCount(1, $templates);
|
||||||
|
|
||||||
// Make sure we can filter our templates by suffix.
|
// Make sure we can filter our templates by suffix.
|
||||||
$templates = SSViewer::get_templates_by_class('SSViewerTest', '_Controller');
|
$templates = SSViewer::get_templates_by_class('SSViewerTest', '_Controller');
|
||||||
$self->assertCount(1, $templates);
|
$self->assertCount(1, $templates);
|
||||||
|
|
||||||
// Test passing a valid object
|
|
||||||
$templates = SSViewer::get_templates_by_class("SSViewerTest_Controller", '', 'Controller');
|
|
||||||
|
|
||||||
// Test that templates are returned in the correct order
|
|
||||||
$self->assertEquals('SSViewerTest_Controller', array_shift($templates));
|
|
||||||
$self->assertEquals('Controller', array_shift($templates));
|
|
||||||
|
|
||||||
// Let's throw something random in there.
|
// Let's throw something random in there.
|
||||||
$self->setExpectedException('InvalidArgumentException');
|
$self->setExpectedException('InvalidArgumentException');
|
||||||
$templates = SSViewer::get_templates_by_class(array());
|
$templates = SSViewer::get_templates_by_class(array());
|
||||||
@ -1593,11 +1593,6 @@ class SSViewerTest_ViewableData extends ViewableData implements TestOnly {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class SSViewerTest_Controller extends Controller {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
class SSViewerTest_Object extends DataObject implements TestOnly {
|
class SSViewerTest_Object extends DataObject implements TestOnly {
|
||||||
|
|
||||||
public $number = null;
|
public $number = null;
|
||||||
@ -1687,4 +1682,3 @@ class SSViewerTest_LevelTest extends ViewableData implements TestOnly {
|
|||||||
return new self($number);
|
return new self($number);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
8
tests/view/TestNamespace/SSViewerTest_Controller.php
Normal file
8
tests/view/TestNamespace/SSViewerTest_Controller.php
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace TestNamespace;
|
||||||
|
|
||||||
|
class SSViewerTest_Controller extends \Controller
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user