diff --git a/docs/en/02_Developer_Guides/01_Templates/03_Requirements.md b/docs/en/02_Developer_Guides/01_Templates/03_Requirements.md
index 251362c87..8cbeb9767 100644
--- a/docs/en/02_Developer_Guides/01_Templates/03_Requirements.md
+++ b/docs/en/02_Developer_Guides/01_Templates/03_Requirements.md
@@ -169,13 +169,13 @@ replaced. For instance, the below will set a new set of dependencies to write to
---
Name: myrequirements
---
- Requirements:
+ SilverStripe\View\Requirements:
disable_flush_combined: true
- Requirements_Backend:
+ SilverStripe\View\Requirements_Backend:
combine_in_dev: true
combine_hash_querystring: true
default_combined_files_folder: 'combined'
- Injector:
+ SilverStripe\Core\Injector\Injector:
MySiteAdapter:
class: 'SilverStripe\Filesystem\Flysystem\AssetAdapter'
constructor:
@@ -192,7 +192,7 @@ replaced. For instance, the below will set a new set of dependencies to write to
class: SilverStripe\Filesystem\Storage\FlysystemGeneratedAssetHandler
properties:
Filesystem: '%$MySiteBackend'
- Requirements_Backend:
+ SilverStripe\View\Requirements_Backend:
properties:
AssetHandler: '%$MySiteAssetHandler'
@@ -248,6 +248,49 @@ $scripts = array(
Requirements::combine_files('scripts.js', $scripts, array('async' => true, 'defer' => true));
```
+### Minification of CSS and JS files
+
+You can minify combined Javascript and CSS files at runtime using an implementation of the
+`SilverStripe\View\Requirements_Minifier` interface.
+
+```php
+namespace MyProject;
+
+use SilverStripe\View\Requirements_Minifier;
+
+class MyMinifier implements Requirements_Minifier
+{
+ /**
+ * Minify the given content
+ *
+ * @param string $content
+ * @param string $type Either js or css
+ * @param string $filename Name of file to display in case of error
+ * @return string minified content
+ */
+ public function minify ($content, $type, $fileName)
+ {
+ // Minify $content;
+
+ return $minifiedContent;
+ }
+}
+```
+
+Then, inject this service in `Requirements_Backend`.
+
+```yaml
+SilverStripe\Core\Injector\Injector:
+ SilverStripe\View\Requirements_Backend:
+ properties:
+ Minifier: %$MyProject\MyMinifier
+```
+
+
+While the framework does afford you the option of minification at runtime, we recommend using one of many frontend build
+tools to do this for you, e.g. [Webpack](https://webpack.github.io/), [Gulp](http://gulpjs.com/), or [Grunt](https://gruntjs.com/).
+
+
## Clearing assets
diff --git a/src/View/JSMinifier.php b/src/View/JSMinifier.php
deleted file mode 100644
index d63be3dd2..000000000
--- a/src/View/JSMinifier.php
+++ /dev/null
@@ -1,30 +0,0 @@
-getMessage();
- user_error("Failed to minify {$filename}, exception: {$message}", E_USER_WARNING);
- } finally {
- return $content . ";\n";
- }
- }
-}
diff --git a/src/View/Requirements_Backend.php b/src/View/Requirements_Backend.php
index 78f642ca7..fa5a26b5e 100644
--- a/src/View/Requirements_Backend.php
+++ b/src/View/Requirements_Backend.php
@@ -3,6 +3,7 @@
namespace SilverStripe\View;
use InvalidArgumentException;
+use Exception;
use SilverStripe\Assets\File;
use SilverStripe\Assets\Storage\GeneratedAssetHandler;
use SilverStripe\Control\Director;
@@ -10,7 +11,6 @@ use SilverStripe\Control\HTTPResponse;
use SilverStripe\Core\Config\Config;
use SilverStripe\Core\Convert;
use SilverStripe\Core\Injector\Injectable;
-use SilverStripe\Core\Injector\Injector;
use SilverStripe\Dev\Debug;
use SilverStripe\Dev\Deprecation;
use SilverStripe\Dev\SapphireTest;
@@ -121,11 +121,11 @@ class Requirements_Backend
protected $combinedFiles = array();
/**
- * Use the JSMin library to minify any javascript file passed to {@link combine_files()}.
+ * Use the injected minification service to minify any javascript file passed to {@link combine_files()}.
*
* @var bool
*/
- protected $minifyCombinedJSFiles = true;
+ protected $minifyCombinedFiles = false;
/**
* Whether or not file headers should be written when combining files
@@ -191,6 +191,11 @@ class Requirements_Backend
*/
protected $assetHandler = null;
+ /**
+ * @var Requirements_Minifier
+ */
+ protected $minifier = null;
+
/**
* Gets the backend storage for generated files
*
@@ -211,6 +216,27 @@ class Requirements_Backend
$this->assetHandler = $handler;
}
+ /**
+ * Gets the minification service for this backend
+ *
+ * @deprecated 4.0..5.0
+ * @return Requirements_Minifier
+ */
+ public function getMinifier()
+ {
+ return $this->minifier;
+ }
+
+ /**
+ * Set a new minification service for this backend
+ *
+ * @param Requirements_Minifier $minifier
+ */
+ public function setMinifier(Requirements_Minifier $minifier = null)
+ {
+ $this->minifier = $minifier;
+ }
+
/**
* Enable or disable the combination of CSS and JavaScript files
*
@@ -340,24 +366,24 @@ class Requirements_Backend
}
/**
- * Check if minify js files should be combined
+ * Check if minify files should be combined
*
* @return bool
*/
- public function getMinifyCombinedJSFiles()
+ public function getMinifyCombinedFiles()
{
- return $this->minifyCombinedJSFiles;
+ return $this->minifyCombinedFiles;
}
/**
- * Set if combined js files should be minified
+ * Set if combined files should be minified
*
* @param bool $minify
* @return $this
*/
- public function setMinifyCombinedJSFiles($minify)
+ public function setMinifyCombinedFiles($minify)
{
- $this->minifyCombinedJSFiles = $minify;
+ $this->minifyCombinedFiles = $minify;
return $this;
}
@@ -1278,7 +1304,20 @@ class Requirements_Backend
$combinedFileID = File::join_paths($this->getCombinedFilesFolder(), $combinedFile);
// Send file combination request to the backend, with an optional callback to perform regeneration
- $minify = $this->getMinifyCombinedJSFiles();
+ $minify = $this->getMinifyCombinedFiles();
+ if ($minify && !$this->minifier) {
+ throw new Exception(
+ sprintf(
+ 'Cannot minify files without a minification service defined.
+ Set %s::minifyCombinedFiles to false, or inject a %s service on
+ %s.properties.minifier',
+ __CLASS__,
+ Requirements_Minifier::class,
+ __CLASS__
+ )
+ );
+ }
+
$combinedURL = $this
->getAssetHandler()
->getContentURL(
@@ -1287,12 +1326,11 @@ class Requirements_Backend
// Physically combine all file content
$combinedData = '';
$base = Director::baseFolder() . '/';
- $minifier = Injector::inst()->get('SilverStripe\\View\\Requirements_Minifier');
foreach ($fileList as $file) {
$fileContent = file_get_contents($base . $file);
// Use configured minifier
if ($minify) {
- $fileContent = $minifier->minify($fileContent, $type, $file);
+ $fileContent = $this->minifier->minify($fileContent, $type, $file);
}
if ($this->writeHeaderComment) {
diff --git a/src/View/Requirements_Minifier.php b/src/View/Requirements_Minifier.php
index 0994d639c..5fc16c413 100644
--- a/src/View/Requirements_Minifier.php
+++ b/src/View/Requirements_Minifier.php
@@ -4,6 +4,8 @@ namespace SilverStripe\View;
/**
* Provides an abstract interface for minifying content
+ *
+ * @deprecated 4.0..5.0
*/
interface Requirements_Minifier
{
diff --git a/tests/php/View/RequirementsTest.php b/tests/php/View/RequirementsTest.php
index 6208fa3e4..85da1a3de 100644
--- a/tests/php/View/RequirementsTest.php
+++ b/tests/php/View/RequirementsTest.php
@@ -86,7 +86,7 @@ class RequirementsTest extends SapphireTest
$backend->clear();
$backend->clearCombinedFiles();
$backend->setCombinedFilesFolder('_combinedfiles');
- $backend->setMinifyCombinedJSFiles(false);
+ $backend->setMinifyCombinedFiles(false);
Requirements::flush();
}
diff --git a/tests/php/View/SSViewerTest.php b/tests/php/View/SSViewerTest.php
index ab83cd0d9..bb58fd184 100644
--- a/tests/php/View/SSViewerTest.php
+++ b/tests/php/View/SSViewerTest.php
@@ -8,7 +8,6 @@ use SilverStripe\Control\ContentNegotiator;
use SilverStripe\Control\HTTPResponse;
use SilverStripe\Core\Convert;
use SilverStripe\Core\Injector\Injector;
-use SilverStripe\Dev\Debug;
use SilverStripe\Dev\SapphireTest;
use SilverStripe\i18n\i18n;
use SilverStripe\ORM\DataObject;
@@ -20,6 +19,7 @@ use SilverStripe\Security\SecurityToken;
use SilverStripe\Security\Permission;
use SilverStripe\View\ArrayData;
use SilverStripe\View\Requirements_Backend;
+use SilverStripe\View\Requirements_Minifier;
use SilverStripe\View\SSViewer;
use SilverStripe\View\Requirements;
use SilverStripe\View\Tests\SSViewerTest\SSViewerTestModel;
@@ -28,7 +28,6 @@ use SilverStripe\View\ViewableData;
use SilverStripe\View\SSViewer_FromString;
use SilverStripe\View\SSTemplateParser;
use SilverStripe\Assets\Tests\Storage\AssetStoreTest\TestAssetStore;
-use JSMin;
use Exception;
class SSViewerTest extends SapphireTest
@@ -70,9 +69,9 @@ class SSViewerTest extends SapphireTest
{
SSViewer::config()->update('theme', 'mytheme');
$this->assertEquals(
- 'mytheme',
- SSViewer::config()->uninherited('theme'),
- 'Current theme is the default - user has not defined one'
+ 'mytheme',
+ SSViewer::config()->uninherited('theme'),
+ 'Current theme is the default - user has not defined one'
);
}
@@ -82,9 +81,9 @@ class SSViewerTest extends SapphireTest
public function testTemplateWithoutHeadRenders()
{
$data = new ArrayData(
- array(
- 'Var' => 'var value'
- )
+ array(
+ 'Var' => 'var value'
+ )
);
$result = $data->renderWith("SSViewerTestPartialTemplate");
@@ -95,12 +94,12 @@ class SSViewerTest extends SapphireTest
{
$data = $this->getScopeInheritanceTestData();
$expected = array(
- 'Item 1 - First-ODD top:Item 1',
- 'Item 2 - EVEN top:Item 2',
- 'Item 3 - ODD top:Item 3',
- 'Item 4 - EVEN top:Item 4',
- 'Item 5 - ODD top:Item 5',
- 'Item 6 - Last-EVEN top:Item 6',
+ 'Item 1 - First-ODD top:Item 1',
+ 'Item 2 - EVEN top:Item 2',
+ 'Item 3 - ODD top:Item 3',
+ 'Item 4 - EVEN top:Item 4',
+ 'Item 5 - ODD top:Item 5',
+ 'Item 6 - Last-EVEN top:Item 6',
);
$result = $data->renderWith('SSViewerTestIncludeScopeInheritance');
@@ -108,12 +107,12 @@ class SSViewerTest extends SapphireTest
// reset results for the tests that include arguments (the title is passed as an arg)
$expected = array(
- 'Item 1 _ Item 1 - First-ODD top:Item 1',
- 'Item 2 _ Item 2 - EVEN top:Item 2',
- 'Item 3 _ Item 3 - ODD top:Item 3',
- 'Item 4 _ Item 4 - EVEN top:Item 4',
- 'Item 5 _ Item 5 - ODD top:Item 5',
- 'Item 6 _ Item 6 - Last-EVEN top:Item 6',
+ 'Item 1 _ Item 1 - First-ODD top:Item 1',
+ 'Item 2 _ Item 2 - EVEN top:Item 2',
+ 'Item 3 _ Item 3 - ODD top:Item 3',
+ 'Item 4 _ Item 4 - EVEN top:Item 4',
+ 'Item 5 _ Item 5 - ODD top:Item 5',
+ 'Item 6 _ Item 6 - Last-EVEN top:Item 6',
);
$result = $data->renderWith('SSViewerTestIncludeScopeInheritanceWithArgs');
@@ -123,32 +122,32 @@ class SSViewerTest extends SapphireTest
public function testIncludeTruthyness()
{
$data = new ArrayData(
+ array(
+ 'Title' => 'TruthyTest',
+ 'Items' => new ArrayList(
array(
- 'Title' => 'TruthyTest',
- 'Items' => new ArrayList(
- array(
- new ArrayData(array('Title' => 'Item 1')),
- new ArrayData(array('Title' => '')),
- new ArrayData(array('Title' => true)),
- new ArrayData(array('Title' => false)),
- new ArrayData(array('Title' => null)),
- new ArrayData(array('Title' => 0)),
- new ArrayData(array('Title' => 7))
- )
- )
+ new ArrayData(array('Title' => 'Item 1')),
+ new ArrayData(array('Title' => '')),
+ new ArrayData(array('Title' => true)),
+ new ArrayData(array('Title' => false)),
+ new ArrayData(array('Title' => null)),
+ new ArrayData(array('Title' => 0)),
+ new ArrayData(array('Title' => 7))
)
+ )
+ )
);
$result = $data->renderWith('SSViewerTestIncludeScopeInheritanceWithArgs');
// We should not end up with empty values appearing as empty
$expected = array(
- 'Item 1 _ Item 1 - First-ODD top:Item 1',
- 'Untitled - EVEN top:',
- '1 _ 1 - ODD top:1',
- 'Untitled - EVEN top:',
- 'Untitled - ODD top:',
- 'Untitled - EVEN top:0',
- '7 _ 7 - Last-ODD top:7'
+ 'Item 1 _ Item 1 - First-ODD top:Item 1',
+ 'Untitled - EVEN top:',
+ '1 _ 1 - ODD top:1',
+ 'Untitled - EVEN top:',
+ 'Untitled - ODD top:',
+ 'Untitled - EVEN top:0',
+ '7 _ 7 - Last-ODD top:7'
);
$this->assertExpectedStrings($result, $expected);
}
@@ -156,19 +155,19 @@ class SSViewerTest extends SapphireTest
private function getScopeInheritanceTestData()
{
return new ArrayData(
+ array(
+ 'Title' => 'TopTitleValue',
+ 'Items' => new ArrayList(
array(
- 'Title' => 'TopTitleValue',
- 'Items' => new ArrayList(
- array(
- new ArrayData(array('Title' => 'Item 1')),
- new ArrayData(array('Title' => 'Item 2')),
- new ArrayData(array('Title' => 'Item 3')),
- new ArrayData(array('Title' => 'Item 4')),
- new ArrayData(array('Title' => 'Item 5')),
- new ArrayData(array('Title' => 'Item 6'))
- )
- )
+ new ArrayData(array('Title' => 'Item 1')),
+ new ArrayData(array('Title' => 'Item 2')),
+ new ArrayData(array('Title' => 'Item 3')),
+ new ArrayData(array('Title' => 'Item 4')),
+ new ArrayData(array('Title' => 'Item 5')),
+ new ArrayData(array('Title' => 'Item 6'))
)
+ )
+ )
);
}
@@ -176,8 +175,8 @@ class SSViewerTest extends SapphireTest
{
foreach ($expected as $expectedStr) {
$this->assertTrue(
- (boolean) preg_match("/{$expectedStr}/", $result),
- "Didn't find '{$expectedStr}' in:\n{$result}"
+ (boolean) preg_match("/{$expectedStr}/", $result),
+ "Didn't find '{$expectedStr}' in:\n{$result}"
);
}
}
@@ -202,7 +201,7 @@ class SSViewerTest extends SapphireTest
public function testRequirements()
{
$requirements = $this->getMockBuilder(Requirements_Backend::class)->setMethods(array("javascript", "css"))
- ->getMock();
+ ->getMock();
$jsFile = FRAMEWORK_DIR . '/tests/forms/a.js';
$cssFile = FRAMEWORK_DIR . '/tests/forms/a.js';
@@ -212,7 +211,7 @@ class SSViewerTest extends SapphireTest
$origReq = Requirements::backend();
Requirements::set_backend($requirements);
$template = $this->render(
- "<% require javascript($jsFile) %>
+ "<% require javascript($jsFile) %>
<% require css($cssFile) %>"
);
Requirements::set_backend($origReq);
@@ -230,15 +229,6 @@ class SSViewerTest extends SapphireTest
$jsFileContents = file_get_contents(BASE_PATH . '/' . $jsFile);
$testBackend->combineFiles('testRequirementsCombine.js', array($jsFile));
- // first make sure that our test js file causes an exception to be thrown
- try {
- include_once 'jsmin/jsmin.php';
- JSMin::minify($jsFileContents);
- $this->fail('JSMin did not throw exception on minify bad file: ');
- } catch (Exception $e) {
- // exception thrown... good
- }
-
// secondly, make sure that requirements is generated, even though minification failed
$testBackend->processCombinedFiles();
$js = array_keys($testBackend->getJavascript());
@@ -253,12 +243,50 @@ class SSViewerTest extends SapphireTest
$this->assertContains($jsFileContents, $combinedTestFileContents);
}
+ public function testRequirementsMinification()
+ {
+ $testBackend = Injector::inst()->create(Requirements_Backend::class);
+ $testBackend->setSuffixRequirements(false);
+ $testBackend->setMinifyCombinedFiles(true);
+ $testFile = $this->getCurrentRelativePath() . '/SSViewerTest/javascript/RequirementsTest_a.js';
+ $testFileContent = file_get_contents($testFile);
+
+ $mockMinifier = $this->getMockBuilder(Requirements_Minifier::class)
+ ->setMethods(['minify'])
+ ->getMock();
+
+ $mockMinifier->expects($this->once())
+ ->method('minify')
+ ->with(
+ $testFileContent,
+ 'js',
+ $testFile
+ );
+ $testBackend->setMinifier($mockMinifier);
+ $testBackend->combineFiles('testRequirementsMinified.js', array($testFile));
+ $testBackend->processCombinedFiles();
+
+ $testBackend->setMinifyCombinedFiles(false);
+ $mockMinifier->expects($this->never())
+ ->method('minify');
+ $testBackend->processCombinedFiles();
+
+ $this->setExpectedExceptionRegExp(
+ Exception::class,
+ '/minification service/'
+ );
+
+ $testBackend->setMinifyCombinedFiles(true);
+ $testBackend->setMinifier(null);
+ $testBackend->processCombinedFiles();
+ }
+
public function testComments()
{
$output = $this->render(
- <<This is some content<%-- this is another comment --%>Final content
<%-- Alone multi
line comment --%>
@@ -300,9 +328,9 @@ SS;
$this->assertEquals('{$Test}', $this->render('{\\$Test}'), 'Escapes can be used to avoid injection');
$this->assertEquals(
- '{\\[out:Test]}',
- $this->render('{\\\\$Test}'),
- 'Escapes before injections are correctly unescaped'
+ '{\\[out:Test]}',
+ $this->render('{\\\\$Test}'),
+ 'Escapes before injections are correctly unescaped'
);
}
@@ -319,12 +347,12 @@ SS;
$this->assertEquals('zz', $this->render('$SSViewerTest_GlobalThatTakesArguments'));
$this->assertEquals('zFooz', $this->render('$SSViewerTest_GlobalThatTakesArguments("Foo")'));
$this->assertEquals(
- 'zFoo:Bar:Bazz',
- $this->render('$SSViewerTest_GlobalThatTakesArguments("Foo", "Bar", "Baz")')
+ 'zFoo:Bar:Bazz',
+ $this->render('$SSViewerTest_GlobalThatTakesArguments("Foo", "Bar", "Baz")')
);
$this->assertEquals(
- 'zreferencez',
- $this->render('$SSViewerTest_GlobalThatTakesArguments($SSViewerTest_GlobalReferencedByString)')
+ 'zreferencez',
+ $this->render('$SSViewerTest_GlobalThatTakesArguments($SSViewerTest_GlobalReferencedByString)')
);
}
@@ -334,101 +362,101 @@ SS;
$this->assertEquals('<div></div>', $this->render('$SSViewerTest_GlobalHTMLEscaped'));
$this->assertEquals(
- 'zz',
- $this->render('$SSViewerTest_GlobalThatTakesArguments($SSViewerTest_GlobalHTMLFragment)')
+ 'zz',
+ $this->render('$SSViewerTest_GlobalThatTakesArguments($SSViewerTest_GlobalHTMLFragment)')
);
$this->assertEquals(
- 'z<div></div>z',
- $this->render('$SSViewerTest_GlobalThatTakesArguments($SSViewerTest_GlobalHTMLEscaped)')
+ 'z<div></div>z',
+ $this->render('$SSViewerTest_GlobalThatTakesArguments($SSViewerTest_GlobalHTMLEscaped)')
);
}
public function testCoreGlobalVariableCalls()
{
$this->assertEquals(
- Director::absoluteBaseURL(),
- $this->render('{$absoluteBaseURL}'),
- 'Director::absoluteBaseURL can be called from within template'
+ Director::absoluteBaseURL(),
+ $this->render('{$absoluteBaseURL}'),
+ 'Director::absoluteBaseURL can be called from within template'
);
$this->assertEquals(
- Director::absoluteBaseURL(),
- $this->render('{$AbsoluteBaseURL}'),
- 'Upper-case %AbsoluteBaseURL can be called from within template'
+ Director::absoluteBaseURL(),
+ $this->render('{$AbsoluteBaseURL}'),
+ 'Upper-case %AbsoluteBaseURL can be called from within template'
);
$this->assertEquals(
- Director::is_ajax(),
- $this->render('{$isAjax}'),
- 'All variations of is_ajax result in the correct call'
+ Director::is_ajax(),
+ $this->render('{$isAjax}'),
+ 'All variations of is_ajax result in the correct call'
);
$this->assertEquals(
- Director::is_ajax(),
- $this->render('{$IsAjax}'),
- 'All variations of is_ajax result in the correct call'
+ Director::is_ajax(),
+ $this->render('{$IsAjax}'),
+ 'All variations of is_ajax result in the correct call'
);
$this->assertEquals(
- Director::is_ajax(),
- $this->render('{$is_ajax}'),
- 'All variations of is_ajax result in the correct call'
+ Director::is_ajax(),
+ $this->render('{$is_ajax}'),
+ 'All variations of is_ajax result in the correct call'
);
$this->assertEquals(
- Director::is_ajax(),
- $this->render('{$Is_ajax}'),
- 'All variations of is_ajax result in the correct call'
+ Director::is_ajax(),
+ $this->render('{$Is_ajax}'),
+ 'All variations of is_ajax result in the correct call'
);
$this->assertEquals(
- i18n::get_locale(),
- $this->render('{$i18nLocale}'),
- 'i18n template functions result correct result'
+ i18n::get_locale(),
+ $this->render('{$i18nLocale}'),
+ 'i18n template functions result correct result'
);
$this->assertEquals(
- i18n::get_locale(),
- $this->render('{$get_locale}'),
- 'i18n template functions result correct result'
+ i18n::get_locale(),
+ $this->render('{$get_locale}'),
+ 'i18n template functions result correct result'
);
$this->assertEquals(
- (string)Member::currentUser(),
- $this->render('{$CurrentMember}'),
- 'Member template functions result correct result'
+ (string)Member::currentUser(),
+ $this->render('{$CurrentMember}'),
+ 'Member template functions result correct result'
);
$this->assertEquals(
- (string)Member::currentUser(),
- $this->render('{$CurrentUser}'),
- 'Member template functions result correct result'
+ (string)Member::currentUser(),
+ $this->render('{$CurrentUser}'),
+ 'Member template functions result correct result'
);
$this->assertEquals(
- (string)Member::currentUser(),
- $this->render('{$currentMember}'),
- 'Member template functions result correct result'
+ (string)Member::currentUser(),
+ $this->render('{$currentMember}'),
+ 'Member template functions result correct result'
);
$this->assertEquals(
- (string)Member::currentUser(),
- $this->render('{$currentUser}'),
- 'Member template functions result correct result'
+ (string)Member::currentUser(),
+ $this->render('{$currentUser}'),
+ 'Member template functions result correct result'
);
$this->assertEquals(
- SecurityToken::getSecurityID(),
- $this->render('{$getSecurityID}'),
- 'SecurityToken template functions result correct result'
+ SecurityToken::getSecurityID(),
+ $this->render('{$getSecurityID}'),
+ 'SecurityToken template functions result correct result'
);
$this->assertEquals(
- SecurityToken::getSecurityID(),
- $this->render('{$SecurityID}'),
- 'SecurityToken template functions result correct result'
+ SecurityToken::getSecurityID(),
+ $this->render('{$SecurityID}'),
+ 'SecurityToken template functions result correct result'
);
$this->assertEquals(
- Permission::check("ADMIN"),
- (bool)$this->render('{$HasPerm(\'ADMIN\')}'),
- 'Permissions template functions result correct result'
+ Permission::check("ADMIN"),
+ (bool)$this->render('{$HasPerm(\'ADMIN\')}'),
+ 'Permissions template functions result correct result'
);
$this->assertEquals(
- Permission::check("ADMIN"),
- (bool)$this->render('{$hasPerm(\'ADMIN\')}'),
- 'Permissions template functions result correct result'
+ Permission::check("ADMIN"),
+ (bool)$this->render('{$hasPerm(\'ADMIN\')}'),
+ 'Permissions template functions result correct result'
);
}
@@ -436,15 +464,15 @@ SS;
{
// check if Link without $ in front of variable
$result = $this->render(
- 'A<% if Link %>$Link<% end_if %>B',
- new SSViewerTest\TestObject()
+ 'A<% if Link %>$Link<% end_if %>B',
+ new SSViewerTest\TestObject()
);
$this->assertEquals('Asome/url.htmlB', $result, 'casting helper not used for <% if Link %>');
// check if Link with $ in front of variable
$result = $this->render(
- 'A<% if $Link %>$Link<% end_if %>B',
- new SSViewerTest\TestObject()
+ 'A<% if $Link %>$Link<% end_if %>B',
+ new SSViewerTest\TestObject()
);
$this->assertEquals('Asome/url.htmlB', $result, 'casting helper not used for <% if $Link %>');
}
@@ -452,15 +480,15 @@ SS;
public function testLocalFunctionsTakePriorityOverGlobals()
{
$data = new ArrayData(
- array(
- 'Page' => new SSViewerTest\TestObject()
- )
+ array(
+ 'Page' => new SSViewerTest\TestObject()
+ )
);
//call method with lots of arguments
$result = $this->render(
- '<% with Page %>$lotsOfArguments11("a","b","c","d","e","f","g","h","i","j","k")<% end_with %>',
- $data
+ '<% with Page %>$lotsOfArguments11("a","b","c","d","e","f","g","h","i","j","k")<% end_with %>',
+ $data
);
$this->assertEquals("abcdefghijk", $result, "public function can accept up to 11 arguments");
@@ -475,9 +503,9 @@ SS;
//call method with same name as a global method (local call should take priority)
$result = $this->render('<% with Page %>$absoluteBaseURL<% end_with %>', $data);
$this->assertEquals(
- "testLocalFunctionPriorityCalled",
- $result,
- "Local Object's public function called. Did not return the actual baseURL of the current site"
+ "testLocalFunctionPriorityCalled",
+ $result,
+ "Local Object's public function called. Did not return the actual baseURL of the current site"
);
}
@@ -485,47 +513,47 @@ SS;
{
// Data to run the loop tests on - one sequence of three items, each with a subitem
$data = new ArrayData(
+ array(
+ 'Foo' => new ArrayList(
array(
- 'Foo' => new ArrayList(
+ 'Subocean' => new ArrayData(
array(
- 'Subocean' => new ArrayData(
- array(
- 'Name' => 'Higher'
- )
- ),
- new ArrayData(
- array(
- 'Sub' => new ArrayData(
- array(
- 'Name' => 'SubKid1'
- )
- )
- )
- ),
- new ArrayData(
- array(
- 'Sub' => new ArrayData(
- array(
- 'Name' => 'SubKid2'
- )
- )
- )
- ),
- new SSViewerTest\TestObject('Number6')
+ 'Name' => 'Higher'
)
+ ),
+ new ArrayData(
+ array(
+ 'Sub' => new ArrayData(
+ array(
+ 'Name' => 'SubKid1'
+ )
+ )
+ )
+ ),
+ new ArrayData(
+ array(
+ 'Sub' => new ArrayData(
+ array(
+ 'Name' => 'SubKid2'
+ )
+ )
+ )
+ ),
+ new SSViewerTest\TestObject('Number6')
)
- )
+ )
+ )
);
$result = $this->render(
- '<% loop Foo %>$Number<% if Sub %><% with Sub %>$Name<% end_with %><% end_if %><% end_loop %>',
- $data
+ '<% loop Foo %>$Number<% if Sub %><% with Sub %>$Name<% end_with %><% end_if %><% end_loop %>',
+ $data
);
$this->assertEquals("SubKid1SubKid2Number6", $result, "Loop works");
$result = $this->render(
- '<% loop Foo %>$Number<% if Sub %><% with Sub %>$Name<% end_with %><% end_if %><% end_loop %>',
- $data
+ '<% loop Foo %>$Number<% if Sub %><% with Sub %>$Name<% end_with %><% end_if %><% end_loop %>',
+ $data
);
$this->assertEquals("SubKid1SubKid2Number6", $result, "Loop works");
@@ -533,16 +561,16 @@ SS;
$this->assertEquals("4", $result, "4 items in the DataObjectSet");
$result = $this->render(
- '<% with Foo %><% loop Up.Foo %>$Number<% if Sub %><% with Sub %>$Name<% end_with %>'
- . '<% end_if %><% end_loop %><% end_with %>',
- $data
+ '<% with Foo %><% loop Up.Foo %>$Number<% if Sub %><% with Sub %>$Name<% end_with %>'
+ . '<% end_if %><% end_loop %><% end_with %>',
+ $data
);
$this->assertEquals("SubKid1SubKid2Number6", $result, "Loop in with Up.Foo scope works");
$result = $this->render(
- '<% with Foo %><% loop %>$Number<% if Sub %><% with Sub %>$Name<% end_with %>'
- . '<% end_if %><% end_loop %><% end_with %>',
- $data
+ '<% with Foo %><% loop %>$Number<% if Sub %><% with Sub %>$Name<% end_with %>'
+ . '<% end_if %><% end_loop %><% end_with %>',
+ $data
);
$this->assertEquals("SubKid1SubKid2Number6", $result, "Loop in current scope works");
}
@@ -550,7 +578,7 @@ SS;
public function testObjectDotArguments()
{
$this->assertEquals(
- '[out:TestObject.methodWithOneArgument(one)]
+ '[out:TestObject.methodWithOneArgument(one)]
[out:TestObject.methodWithTwoArguments(one,two)]
[out:TestMethod(Arg1,Arg2).Bar.Val]
[out:TestMethod(Arg1,Arg2).Bar]
@@ -558,8 +586,8 @@ SS;
[out:TestMethod(Arg1).Bar.Val]
[out:TestMethod(Arg1).Bar]
[out:TestMethod(Arg1)]',
- $this->render(
- '$TestObject.methodWithOneArgument(one)
+ $this->render(
+ '$TestObject.methodWithOneArgument(one)
$TestObject.methodWithTwoArguments(one,two)
$TestMethod(Arg1, Arg2).Bar.Val
$TestMethod(Arg1, Arg2).Bar
@@ -567,14 +595,14 @@ SS;
$TestMethod(Arg1).Bar.Val
$TestMethod(Arg1).Bar
$TestMethod(Arg1)'
- )
+ )
);
}
public function testEscapedArguments()
{
$this->assertEquals(
- '[out:Foo(Arg1,Arg2).Bar.Val].Suffix
+ '[out:Foo(Arg1,Arg2).Bar.Val].Suffix
[out:Foo(Arg1,Arg2).Val]_Suffix
[out:Foo(Arg1,Arg2)]/Suffix
[out:Foo(Arg1).Bar.Val]textSuffix
@@ -583,8 +611,8 @@ SS;
[out:Foo.Bar.Val].Suffix
[out:Foo.Bar].Suffix
[out:Foo].Suffix',
- $this->render(
- '{$Foo(Arg1, Arg2).Bar.Val}.Suffix
+ $this->render(
+ '{$Foo(Arg1, Arg2).Bar.Val}.Suffix
{$Foo(Arg1, Arg2).Val}_Suffix
{$Foo(Arg1, Arg2)}/Suffix
{$Foo(Arg1).Bar.Val}textSuffix
@@ -593,44 +621,44 @@ SS;
{$Foo.Bar.Val}.Suffix
{$Foo.Bar}.Suffix
{$Foo}.Suffix'
- )
+ )
);
}
public function testLoopWhitespace()
{
$this->assertEquals(
- 'before[out:SingleItem.Test]after
+ 'before[out:SingleItem.Test]after
beforeTestafter',
- $this->render(
- 'before<% loop SingleItem %>$Test<% end_loop %>after
+ $this->render(
+ 'before<% loop SingleItem %>$Test<% end_loop %>after
before<% loop SingleItem %>Test<% end_loop %>after'
- )
+ )
);
// The control tags are removed from the output, but no whitespace
// This is a quirk that could be changed, but included in the test to make the current
// behaviour explicit
$this->assertEquals(
- 'before
+ 'before
[out:SingleItem.ItemOnItsOwnLine]
after',
- $this->render(
- 'before
+ $this->render(
+ 'before
<% loop SingleItem %>
$ItemOnItsOwnLine
<% end_loop %>
after'
- )
+ )
);
// The whitespace within the control tags is preserve in a loop
// This is a quirk that could be changed, but included in the test to make the current
// behaviour explicit
$this->assertEquals(
- 'before
+ 'before
[out:Loop3.ItemOnItsOwnLine]
@@ -639,13 +667,13 @@ after'
[out:Loop3.ItemOnItsOwnLine]
after',
- $this->render(
- 'before
+ $this->render(
+ 'before
<% loop Loop3 %>
$ItemOnItsOwnLine
<% end_loop %>
after'
- )
+ )
);
}
@@ -653,44 +681,44 @@ after'
{
// Single item controls
$this->assertEquals(
- 'a[out:Foo.Bar.Item]b
+ 'a[out:Foo.Bar.Item]b
[out:Foo.Bar(Arg1).Item]
[out:Foo(Arg1).Item]
[out:Foo(Arg1,Arg2).Item]
[out:Foo(Arg1,Arg2,Arg3).Item]',
- $this->render(
- '<% with Foo.Bar %>a{$Item}b<% end_with %>
+ $this->render(
+ '<% with Foo.Bar %>a{$Item}b<% end_with %>
<% with Foo.Bar(Arg1) %>$Item<% end_with %>
<% with Foo(Arg1) %>$Item<% end_with %>
<% with Foo(Arg1, Arg2) %>$Item<% end_with %>
<% with Foo(Arg1, Arg2, Arg3) %>$Item<% end_with %>'
- )
+ )
);
// Loop controls
$this->assertEquals(
- 'a[out:Foo.Loop2.Item]ba[out:Foo.Loop2.Item]b',
- $this->render('<% loop Foo.Loop2 %>a{$Item}b<% end_loop %>')
+ 'a[out:Foo.Loop2.Item]ba[out:Foo.Loop2.Item]b',
+ $this->render('<% loop Foo.Loop2 %>a{$Item}b<% end_loop %>')
);
$this->assertEquals(
- '[out:Foo.Loop2(Arg1).Item][out:Foo.Loop2(Arg1).Item]',
- $this->render('<% loop Foo.Loop2(Arg1) %>$Item<% end_loop %>')
+ '[out:Foo.Loop2(Arg1).Item][out:Foo.Loop2(Arg1).Item]',
+ $this->render('<% loop Foo.Loop2(Arg1) %>$Item<% end_loop %>')
);
$this->assertEquals(
- '[out:Loop2(Arg1).Item][out:Loop2(Arg1).Item]',
- $this->render('<% loop Loop2(Arg1) %>$Item<% end_loop %>')
+ '[out:Loop2(Arg1).Item][out:Loop2(Arg1).Item]',
+ $this->render('<% loop Loop2(Arg1) %>$Item<% end_loop %>')
);
$this->assertEquals(
- '[out:Loop2(Arg1,Arg2).Item][out:Loop2(Arg1,Arg2).Item]',
- $this->render('<% loop Loop2(Arg1, Arg2) %>$Item<% end_loop %>')
+ '[out:Loop2(Arg1,Arg2).Item][out:Loop2(Arg1,Arg2).Item]',
+ $this->render('<% loop Loop2(Arg1, Arg2) %>$Item<% end_loop %>')
);
$this->assertEquals(
- '[out:Loop2(Arg1,Arg2,Arg3).Item][out:Loop2(Arg1,Arg2,Arg3).Item]',
- $this->render('<% loop Loop2(Arg1, Arg2, Arg3) %>$Item<% end_loop %>')
+ '[out:Loop2(Arg1,Arg2,Arg3).Item][out:Loop2(Arg1,Arg2,Arg3).Item]',
+ $this->render('<% loop Loop2(Arg1, Arg2, Arg3) %>$Item<% end_loop %>')
);
}
@@ -698,139 +726,139 @@ after'
{
// Basic test
$this->assertEquals(
- 'AC',
- $this->render('A<% if NotSet %>B$NotSet<% end_if %>C')
+ 'AC',
+ $this->render('A<% if NotSet %>B$NotSet<% end_if %>C')
);
// Nested test
$this->assertEquals(
- 'AB1C',
- $this->render('A<% if IsSet %>B$NotSet<% if IsSet %>1<% else %>2<% end_if %><% end_if %>C')
+ 'AB1C',
+ $this->render('A<% if IsSet %>B$NotSet<% if IsSet %>1<% else %>2<% end_if %><% end_if %>C')
);
// else_if
$this->assertEquals(
- 'ACD',
- $this->render('A<% if NotSet %>B<% else_if IsSet %>C<% end_if %>D')
+ 'ACD',
+ $this->render('A<% if NotSet %>B<% else_if IsSet %>C<% end_if %>D')
);
$this->assertEquals(
- 'AD',
- $this->render('A<% if NotSet %>B<% else_if AlsoNotset %>C<% end_if %>D')
+ 'AD',
+ $this->render('A<% if NotSet %>B<% else_if AlsoNotset %>C<% end_if %>D')
);
$this->assertEquals(
- 'ADE',
- $this->render('A<% if NotSet %>B<% else_if AlsoNotset %>C<% else_if IsSet %>D<% end_if %>E')
+ 'ADE',
+ $this->render('A<% if NotSet %>B<% else_if AlsoNotset %>C<% else_if IsSet %>D<% end_if %>E')
);
$this->assertEquals(
- 'ADE',
- $this->render('A<% if NotSet %>B<% else_if AlsoNotset %>C<% else_if IsSet %>D<% end_if %>E')
+ 'ADE',
+ $this->render('A<% if NotSet %>B<% else_if AlsoNotset %>C<% else_if IsSet %>D<% end_if %>E')
);
// Dot syntax
$this->assertEquals(
- 'ACD',
- $this->render('A<% if Foo.NotSet %>B<% else_if Foo.IsSet %>C<% end_if %>D')
+ 'ACD',
+ $this->render('A<% if Foo.NotSet %>B<% else_if Foo.IsSet %>C<% end_if %>D')
);
$this->assertEquals(
- 'ACD',
- $this->render('A<% if Foo.Bar.NotSet %>B<% else_if Foo.Bar.IsSet %>C<% end_if %>D')
+ 'ACD',
+ $this->render('A<% if Foo.Bar.NotSet %>B<% else_if Foo.Bar.IsSet %>C<% end_if %>D')
);
// Params
$this->assertEquals(
- 'ACD',
- $this->render('A<% if NotSet(Param) %>B<% else %>C<% end_if %>D')
+ 'ACD',
+ $this->render('A<% if NotSet(Param) %>B<% else %>C<% end_if %>D')
);
$this->assertEquals(
- 'ABD',
- $this->render('A<% if IsSet(Param) %>B<% else %>C<% end_if %>D')
+ 'ABD',
+ $this->render('A<% if IsSet(Param) %>B<% else %>C<% end_if %>D')
);
// Negation
$this->assertEquals(
- 'AC',
- $this->render('A<% if not IsSet %>B<% end_if %>C')
+ 'AC',
+ $this->render('A<% if not IsSet %>B<% end_if %>C')
);
$this->assertEquals(
- 'ABC',
- $this->render('A<% if not NotSet %>B<% end_if %>C')
+ 'ABC',
+ $this->render('A<% if not NotSet %>B<% end_if %>C')
);
// Or
$this->assertEquals(
- 'ABD',
- $this->render('A<% if IsSet || NotSet %>B<% else_if A %>C<% end_if %>D')
+ 'ABD',
+ $this->render('A<% if IsSet || NotSet %>B<% else_if A %>C<% end_if %>D')
);
$this->assertEquals(
- 'ACD',
- $this->render('A<% if NotSet || AlsoNotSet %>B<% else_if IsSet %>C<% end_if %>D')
+ 'ACD',
+ $this->render('A<% if NotSet || AlsoNotSet %>B<% else_if IsSet %>C<% end_if %>D')
);
$this->assertEquals(
- 'AD',
- $this->render('A<% if NotSet || AlsoNotSet %>B<% else_if NotSet3 %>C<% end_if %>D')
+ 'AD',
+ $this->render('A<% if NotSet || AlsoNotSet %>B<% else_if NotSet3 %>C<% end_if %>D')
);
$this->assertEquals(
- 'ACD',
- $this->render('A<% if NotSet || AlsoNotSet %>B<% else_if IsSet || NotSet %>C<% end_if %>D')
+ 'ACD',
+ $this->render('A<% if NotSet || AlsoNotSet %>B<% else_if IsSet || NotSet %>C<% end_if %>D')
);
$this->assertEquals(
- 'AD',
- $this->render('A<% if NotSet || AlsoNotSet %>B<% else_if NotSet2 || NotSet3 %>C<% end_if %>D')
+ 'AD',
+ $this->render('A<% if NotSet || AlsoNotSet %>B<% else_if NotSet2 || NotSet3 %>C<% end_if %>D')
);
// Negated Or
$this->assertEquals(
- 'ACD',
- $this->render('A<% if not IsSet || AlsoNotSet %>B<% else_if A %>C<% end_if %>D')
+ 'ACD',
+ $this->render('A<% if not IsSet || AlsoNotSet %>B<% else_if A %>C<% end_if %>D')
);
$this->assertEquals(
- 'ABD',
- $this->render('A<% if not NotSet || AlsoNotSet %>B<% else_if A %>C<% end_if %>D')
+ 'ABD',
+ $this->render('A<% if not NotSet || AlsoNotSet %>B<% else_if A %>C<% end_if %>D')
);
$this->assertEquals(
- 'ABD',
- $this->render('A<% if NotSet || not AlsoNotSet %>B<% else_if A %>C<% end_if %>D')
+ 'ABD',
+ $this->render('A<% if NotSet || not AlsoNotSet %>B<% else_if A %>C<% end_if %>D')
);
// And
$this->assertEquals(
- 'ABD',
- $this->render('A<% if IsSet && AlsoSet %>B<% else_if A %>C<% end_if %>D')
+ 'ABD',
+ $this->render('A<% if IsSet && AlsoSet %>B<% else_if A %>C<% end_if %>D')
);
$this->assertEquals(
- 'ACD',
- $this->render('A<% if IsSet && NotSet %>B<% else_if IsSet %>C<% end_if %>D')
+ 'ACD',
+ $this->render('A<% if IsSet && NotSet %>B<% else_if IsSet %>C<% end_if %>D')
);
$this->assertEquals(
- 'AD',
- $this->render('A<% if NotSet && NotSet2 %>B<% else_if NotSet3 %>C<% end_if %>D')
+ 'AD',
+ $this->render('A<% if NotSet && NotSet2 %>B<% else_if NotSet3 %>C<% end_if %>D')
);
$this->assertEquals(
- 'ACD',
- $this->render('A<% if IsSet && NotSet %>B<% else_if IsSet && AlsoSet %>C<% end_if %>D')
+ 'ACD',
+ $this->render('A<% if IsSet && NotSet %>B<% else_if IsSet && AlsoSet %>C<% end_if %>D')
);
$this->assertEquals(
- 'AD',
- $this->render('A<% if NotSet && NotSet2 %>B<% else_if IsSet && NotSet3 %>C<% end_if %>D')
+ 'AD',
+ $this->render('A<% if NotSet && NotSet2 %>B<% else_if IsSet && NotSet3 %>C<% end_if %>D')
);
// Equality
$this->assertEquals(
- 'ABC',
- $this->render('A<% if RawVal == RawVal %>B<% end_if %>C')
+ 'ABC',
+ $this->render('A<% if RawVal == RawVal %>B<% end_if %>C')
);
$this->assertEquals(
- 'ACD',
- $this->render('A<% if Right == Wrong %>B<% else_if RawVal == RawVal %>C<% end_if %>D')
+ 'ACD',
+ $this->render('A<% if Right == Wrong %>B<% else_if RawVal == RawVal %>C<% end_if %>D')
);
$this->assertEquals(
- 'ABC',
- $this->render('A<% if Right != Wrong %>B<% end_if %>C')
+ 'ABC',
+ $this->render('A<% if Right != Wrong %>B<% end_if %>C')
);
$this->assertEquals(
- 'AD',
- $this->render('A<% if Right == Wrong %>B<% else_if RawVal != RawVal %>C<% end_if %>D')
+ 'AD',
+ $this->render('A<% if Right == Wrong %>B<% else_if RawVal != RawVal %>C<% end_if %>D')
);
// test inequalities with simple numbers
@@ -853,30 +881,30 @@ after'
// the output would stop after A, thereby failing the assert
$this->assertEquals('AD', $this->render('A<% if IsSet %><% else %><% end_if %>D'));
$this->assertEquals(
- 'AD',
- $this->render('A<% if NotSet %><% else_if IsSet %><% else %><% end_if %>D')
+ 'AD',
+ $this->render('A<% if NotSet %><% else_if IsSet %><% else %><% end_if %>D')
);
$this->assertEquals(
- 'AD',
- $this->render('A<% if NotSet %><% else_if AlsoNotSet %><% else %><% end_if %>D')
+ 'AD',
+ $this->render('A<% if NotSet %><% else_if AlsoNotSet %><% else %><% end_if %>D')
);
// Bare words with ending space
$this->assertEquals(
- 'ABC',
- $this->render('A<% if "RawVal" == RawVal %>B<% end_if %>C')
+ 'ABC',
+ $this->render('A<% if "RawVal" == RawVal %>B<% end_if %>C')
);
// Else
$this->assertEquals(
- 'ADE',
- $this->render('A<% if Right == Wrong %>B<% else_if RawVal != RawVal %>C<% else %>D<% end_if %>E')
+ 'ADE',
+ $this->render('A<% if Right == Wrong %>B<% else_if RawVal != RawVal %>C<% else %>D<% end_if %>E')
);
// Empty if with else
$this->assertEquals(
- 'ABC',
- $this->render('A<% if NotSet %><% else %>B<% end_if %>C')
+ 'ABC',
+ $this->render('A<% if NotSet %><% else %>B<% end_if %>C')
);
}
@@ -885,7 +913,7 @@ after'
// XHTML wil have a closed base tag
$tmpl1 = '
+ . ' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<% base_tag %>