diff --git a/core/Requirements.php b/core/Requirements.php index 00fd16a63..7a35cdf42 100644 --- a/core/Requirements.php +++ b/core/Requirements.php @@ -11,27 +11,19 @@ class Requirements { /** * Enable combining of css/javascript files. - * - * @var boolean + * @param boolean $enable */ - private static $combined_files_enabled = true; - public static function set_combined_files_enabled($enable) { - self::$combined_files_enabled = (bool) $enable; - } - - public static function get_combined_files_enabled() { - return self::$combined_files_enabled; + self::backend()->set_combined_files_enabled($enable); } /** - * Do we want requirements to suffix onto the requirement link - * tags for caching or is it disabled. Getter / Setter available - * through {@link Requirements::set_suffix_requirements()} - * - * @var bool + * Checks whether combining of css/javascript files is enabled. + * @return boolean */ - private static $suffix_requirements = true; + public static function get_combined_files_enabled() { + return self::backend()->get_combined_files_enabled(); + } /** * Set whether we want to suffix requirements with the time / @@ -40,7 +32,7 @@ class Requirements { * @param bool */ public static function set_suffix_requirements($var) { - self::$suffix_requirements = $var; + self::backend()->set_suffix_requirements($var); } /** @@ -49,7 +41,7 @@ class Requirements { * @return bool */ public static function get_suffix_requirements() { - return self::$suffix_requirements; + return self::backend()->get_suffix_requirements(); } /** @@ -58,10 +50,10 @@ class Requirements { * @var Requirements */ private static $backend = null; + public static function backend() { if(!self::$backend) { self::$backend = new Requirements_Backend(); - } return self::$backend; } @@ -74,7 +66,6 @@ class Requirements { public static function set_backend(Requirements_Backend $backend) { self::$backend = $backend; } - /** * Register the given javascript file as required. @@ -86,7 +77,6 @@ class Requirements { self::backend()->javascript($file); } - /** * Add the javascript code to the header of the page * @@ -120,8 +110,6 @@ class Requirements { static function insertHeadTags($html, $uniquenessID = null) { self::backend()->insertHeadTags($html, $uniquenessID); } - - /** * Load the given javascript template with the page. @@ -196,7 +184,6 @@ class Requirements { self::backend()->unblock_all(); } - /** * Restore requirements cleared by call to Requirements::clear * See {@link Requirements_Backend::restore()} @@ -310,16 +297,33 @@ class Requirements { * @subpackage view */ class Requirements_Backend { - /** + + /** + * Do we want requirements to suffix onto the requirement link + * tags for caching or is it disabled. Getter / Setter available + * through {@link Requirements::set_suffix_requirements()} + * + * @var bool + */ + protected $suffix_requirements = true; + + /** + * Enable combining of css/javascript files. + * + * @var boolean + */ + protected $combined_files_enabled = true; + + /** * Paths to all required .js files relative to the webroot. - * + * * @var array $javascript */ protected $javascript = array(); /** * Paths to all required .css files relative to the webroot. - * + * * @var array $css */ protected $css = array(); @@ -334,7 +338,7 @@ class Requirements_Backend { /** * All custom CSS rules which are inserted - * directly at the bottom of the HTML
tag. + * directly at the bottom of the HTML tag. * * @var array $customCSS */ @@ -343,7 +347,7 @@ class Requirements_Backend { /** * All custom HTML markup which is added before * the closing tag, e.g. additional metatags. - * This is preferred to entering tags directly into + * This is preferred to entering tags directly into */ protected $customHeadTags = array(); @@ -354,7 +358,7 @@ class Requirements_Backend { * @var array $disabled */ protected $disabled = array(); - + /** * The filepaths (relative to webroot) or * uniquenessIDs of any included requirements @@ -362,18 +366,18 @@ class Requirements_Backend { * This is useful to e.g. prevent core classes to modifying * Requirements without subclassing the entire functionality. * Use {@link unblock()} or {@link unblock_all()} to revert changes. - * + * * @var array $blocked */ protected $blocked = array(); - + /** * See {@link combine_files()}. - * + * * @var array $combine_files */ public $combine_files = array(); - + /** * Using the JSMin library to minify any * javascript file passed to {@link combine_files()}. @@ -381,7 +385,7 @@ class Requirements_Backend { * @var boolean */ public $combine_js_with_jsmin = true; - + /** * Put all javascript includes at the bottom of the template * before the closing tag instead of the tag. @@ -397,6 +401,33 @@ class Requirements_Backend { */ public $write_js_to_body = true; + function set_combined_files_enabled($enable) { + $this->combined_files_enabled = (bool) $enable; + } + + function get_combined_files_enabled() { + return $this->combined_files_enabled; + } + + /** + * Set whether we want to suffix requirements with the time / + * location on to the requirements + * + * @param bool + */ + function set_suffix_requirements($var) { + $this->suffix_requirements = $var; + } + + /** + * Return whether we want to suffix requirements + * + * @return bool + */ + function get_suffix_requirements() { + return $this->suffix_requirements; + } + /** * Set whether you want the files written to the head or the body. It * writes to the body by default which can break some scripts @@ -585,7 +616,7 @@ class Requirements_Backend { $this->process_combined_files(); foreach(array_diff_key($this->javascript,$this->blocked) as $file => $dummy) { - $path = self::path_for_file($file); + $path = $this->path_for_file($file); if($path) { $jsRequirements .= "\n"; } @@ -602,7 +633,7 @@ class Requirements_Backend { } foreach(array_diff_key($this->css,$this->blocked) as $file => $params) { - $path = self::path_for_file($file); + $path = $this->path_for_file($file); if($path) { $media = (isset($params['media']) && !empty($params['media'])) ? " media=\"{$params['media']}\"" : ""; $requirements .= "\n"; @@ -697,7 +728,7 @@ class Requirements_Backend { * @param string $fileOrUrl * @return string|boolean */ - protected static function path_for_file($fileOrUrl) { + protected function path_for_file($fileOrUrl) { if(preg_match('/^http[s]?/', $fileOrUrl)) { return $fileOrUrl; } elseif(Director::fileExists($fileOrUrl)) { @@ -708,7 +739,7 @@ class Requirements_Backend { $suffix = '&' . substr($fileOrUrl, strpos($fileOrUrl, '?')+1); $fileOrUrl = substr($fileOrUrl, 0, strpos($fileOrUrl, '?')); } - if(Requirements::get_suffix_requirements()) { + if($this->suffix_requirements) { $mtimesuffix = "?m=" . filemtime(Director::baseFolder() . '/' . $fileOrUrl); } return "{$prefix}{$fileOrUrl}{$mtimesuffix}{$suffix}"; @@ -776,7 +807,7 @@ class Requirements_Backend { foreach($this->combine_files as $_combinedFileName => $_files) { $duplicates = array_intersect($_files, $files); if($duplicates) { - user_error("Requirements::combine_files(): Already included files " . implode(',', $duplicates) . " in combined file '{$_combinedFileName}'", E_USER_NOTICE); + user_error("Requirements_Backend::combine_files(): Already included files " . implode(',', $duplicates) . " in combined file '{$_combinedFileName}'", E_USER_NOTICE); return false; } } @@ -822,7 +853,7 @@ class Requirements_Backend { if(class_exists('SapphireTest',false)) $runningTest = SapphireTest::is_running_test(); else $runningTest = false; - if((Director::isDev() && !$runningTest) || !Requirements::get_combined_files_enabled()) { + if((Director::isDev() && !$runningTest) || !$this->combined_files_enabled) { return; } @@ -831,7 +862,7 @@ class Requirements_Backend { foreach($this->combine_files as $combinedFile => $sourceItems) { foreach($sourceItems as $sourceItem) { if(isset($combinerCheck[$sourceItem]) && $combinerCheck[$sourceItem] != $combinedFile){ - user_error("Requirements::process_combined_files - file '$sourceItem' appears in two combined files:" . " '{$combinerCheck[$sourceItem]}' and '$combinedFile'", E_USER_WARNING); + user_error("Requirements_Backend::process_combined_files - file '$sourceItem' appears in two combined files:" . " '{$combinerCheck[$sourceItem]}' and '$combinedFile'", E_USER_WARNING); } $combinerCheck[$sourceItem] = $combinedFile; @@ -947,7 +978,7 @@ class Requirements_Backend { if($theme && isset($_CSS_MANIFEST[$name]) && isset($_CSS_MANIFEST[$name]['themes']) && isset($_CSS_MANIFEST[$name]['themes'][$theme])) - Requirements::css($_CSS_MANIFEST[$name]['themes'][$theme], $media); + $this->css($_CSS_MANIFEST[$name]['themes'][$theme], $media); else if(isset($_CSS_MANIFEST[$name]) && isset($_CSS_MANIFEST[$name]['unthemed'])) $this->css($_CSS_MANIFEST[$name]['unthemed'], $media); // Normal requirements fails quietly when there is no css - we should do the same diff --git a/tests/forms/RequirementsTest.php b/tests/forms/RequirementsTest.php index a8aef3ad4..3c294ac97 100644 --- a/tests/forms/RequirementsTest.php +++ b/tests/forms/RequirementsTest.php @@ -10,28 +10,16 @@ class RequirementsTest extends SapphireTest { static $html_template = ''; - protected $orig = array(); - - function setUp() { - parent::setUp(); - - $this->orig['SetCombineFiles'] = Requirements::get_combined_files_enabled(); - Requirements::set_combined_files_enabled(true); - } - - function tearDown() { - parent::tearDown(); - - Requirements::set_combined_files_enabled($this->orig['SetCombineFiles']); - } - function testExternalUrls() { - Requirements::javascript('http://www.mydomain.com/test.js'); - Requirements::javascript('https://www.mysecuredomain.com/test.js'); - Requirements::css('http://www.mydomain.com/test.css'); - Requirements::css('https://www.mysecuredomain.com/test.css'); + $backend = new Requirements_Backend; + $backend->set_combined_files_enabled(true); + + $backend->javascript('http://www.mydomain.com/test.js'); + $backend->javascript('https://www.mysecuredomain.com/test.js'); + $backend->css('http://www.mydomain.com/test.css'); + $backend->css('https://www.mysecuredomain.com/test.css'); - $html = Requirements::includeInHTML(false, self::$html_template); + $html = $backend->includeInHTML(false, self::$html_template); $this->assertTrue( (strpos($html, 'http://www.mydomain.com/test.js') !== false), @@ -50,13 +38,38 @@ class RequirementsTest extends SapphireTest { 'Load external secure CSS URL' ); } - + + protected function setupCombinedRequirements($backend) { + $backend->clear(); + + // clearing all previously generated requirements (just in case) + $backend->clear_combined_files(); + $backend->delete_combined_files('RequirementsTest_bc.js'); + + // require files normally (e.g. called from a FormField instance) + $backend->javascript(SAPPHIRE_DIR . '/tests/forms/RequirementsTest_a.js'); + $backend->javascript(SAPPHIRE_DIR . '/tests/forms/RequirementsTest_b.js'); + $backend->javascript(SAPPHIRE_DIR . '/tests/forms/RequirementsTest_c.js'); + + // require two of those files as combined includes + $backend->combine_files( + 'RequirementsTest_bc.js', + array( + SAPPHIRE_DIR . '/tests/forms/RequirementsTest_b.js', + SAPPHIRE_DIR . '/tests/forms/RequirementsTest_c.js' + ) + ); + } + function testCombinedJavascript() { - $this->setupCombinedRequirements(); + $backend = new Requirements_Backend; + $backend->set_combined_files_enabled(true); + + $this->setupCombinedRequirements($backend); $combinedFilePath = Director::baseFolder() . '/' . 'RequirementsTest_bc.js'; - $html = Requirements::includeInHTML(false, self::$html_template); + $html = $backend->includeInHTML(false, self::$html_template); /* COMBINED JAVASCRIPT FILE IS INCLUDED IN HTML HEADER */ $this->assertTrue((bool)preg_match('/src=".*\/RequirementsTest_bc\.js/', $html), 'combined javascript file is included in html header'); @@ -75,40 +88,41 @@ class RequirementsTest extends SapphireTest { /* NORMAL REQUIREMENTS ARE STILL INCLUDED */ $this->assertTrue((bool)preg_match('/src=".*\/RequirementsTest_a\.js/', $html), 'normal requirements are still included'); - Requirements::delete_combined_files('RequirementsTest_bc.js'); + $backend->delete_combined_files('RequirementsTest_bc.js'); } function testBlockedCombinedJavascript() { + $backend = new Requirements_Backend; + $backend->set_combined_files_enabled(true); + $combinedFilePath = Director::baseFolder() . '/' . 'RequirementsTest_bc.js'; /* BLOCKED COMBINED FILES ARE NOT INCLUDED */ - $this->setupCombinedRequirements(); - Requirements::block('RequirementsTest_bc.js'); - Requirements::delete_combined_files('RequirementsTest_bc.js'); + $this->setupCombinedRequirements($backend); + $backend->block('RequirementsTest_bc.js'); + $backend->delete_combined_files('RequirementsTest_bc.js'); clearstatcache(); // needed to get accurate file_exists() results - $html = Requirements::includeInHTML(false, self::$html_template); + $html = $backend->includeInHTML(false, self::$html_template); $this->assertFalse((bool)preg_match('/src=".*\/RequirementsTest_bc\.js/', $html), 'blocked combined files are not included '); - Requirements::unblock('RequirementsTest_bc.js'); + $backend->unblock('RequirementsTest_bc.js'); /* BLOCKED UNCOMBINED FILES ARE NOT INCLUDED */ - // need to re-add requirements, as Requirements::process_combined_includes() alters the - // original arrays grml... - $this->setupCombinedRequirements(); - Requirements::block('sapphire/tests/forms/RequirementsTest_b.js'); - Requirements::delete_combined_files('RequirementsTest_bc.js'); + $this->setupCombinedRequirements($backend); + $backend->block('sapphire/tests/forms/RequirementsTest_b.js'); + $backend->delete_combined_files('RequirementsTest_bc.js'); clearstatcache(); // needed to get accurate file_exists() results - $html = Requirements::includeInHTML(false, self::$html_template); + $html = $backend->includeInHTML(false, self::$html_template); $this->assertFalse((strpos(file_get_contents($combinedFilePath), "alert('b')") !== false), 'blocked uncombined files are not included'); - Requirements::unblock('RequirementsTest_b.js'); + $backend->unblock('RequirementsTest_b.js'); /* A SINGLE FILE CAN'T BE INCLUDED IN TWO COMBINED FILES */ - $this->setupCombinedRequirements(); + $this->setupCombinedRequirements($backend); clearstatcache(); // needed to get accurate file_exists() results // This throws a notice-level error, so we prefix with @ - @Requirements::combine_files( + @$backend->combine_files( 'RequirementsTest_ac.js', array( 'sapphire/tests/forms/RequirementsTest_a.js', @@ -116,28 +130,25 @@ class RequirementsTest extends SapphireTest { ) ); - $combinedFiles = Requirements::get_combine_files(); + $combinedFiles = $backend->get_combine_files(); $this->assertEquals( array_keys($combinedFiles), array('RequirementsTest_bc.js'), "A single file can't be included in two combined files" ); - Requirements::delete_combined_files('RequirementsTest_bc.js'); + $backend->delete_combined_files('RequirementsTest_bc.js'); } function testArgsInUrls() { - // Clear previous requirements - Requirements::clear(); + $backend = new Requirements_Backend; + $backend->set_combined_files_enabled(true); - // clearing all previously generated requirements (just in case) - Requirements::clear_combined_files(); + $backend->javascript(SAPPHIRE_DIR . '/tests/forms/RequirementsTest_a.js?test=1&test=2&test=3'); + $backend->css(SAPPHIRE_DIR . '/tests/forms/RequirementsTest_a.css?test=1&test=2&test=3'); Requirements::delete_combined_files('RequirementsTest_bc.js'); - Requirements::javascript(SAPPHIRE_DIR . '/tests/forms/RequirementsTest_a.js?test=1&test=2&test=3'); - Requirements::css(SAPPHIRE_DIR . '/tests/forms/RequirementsTest_a.css?test=1&test=2&test=3'); - - $html = Requirements::includeInHTML(false, self::$html_template); + $html = $backend->includeInHTML(false, self::$html_template); /* Javascript has correct path */ $this->assertTrue((bool)preg_match('/src=".*\/RequirementsTest_a\.js\?m=\d\d+&test=1&test=2&test=3/', $html), 'javascript has correct path'); @@ -146,55 +157,27 @@ class RequirementsTest extends SapphireTest { $this->assertTrue((bool)preg_match('/href=".*\/RequirementsTest_a\.css\?m=\d\d+&test=1&test=2&test=3/', $html), 'css has correct path'); } - /** - * This is a bit of a hack, as it alters the Requirements - * statics globally for all tests. - * - * @todo Refactor Requirements to work on test instance level - */ - protected function setupCombinedRequirements() { - Requirements::clear(); - - // clearing all previously generated requirements (just in case) - Requirements::clear_combined_files(); - Requirements::delete_combined_files('RequirementsTest_bc.js'); - - // require files normally (e.g. called from a FormField instance) - Requirements::javascript(SAPPHIRE_DIR . '/tests/forms/RequirementsTest_a.js'); - Requirements::javascript(SAPPHIRE_DIR . '/tests/forms/RequirementsTest_b.js'); - Requirements::javascript(SAPPHIRE_DIR . '/tests/forms/RequirementsTest_c.js'); - - // require two of those files as combined includes - Requirements::combine_files( - 'RequirementsTest_bc.js', - array( - SAPPHIRE_DIR . '/tests/forms/RequirementsTest_b.js', - SAPPHIRE_DIR . '/tests/forms/RequirementsTest_c.js' - ) - ); - } - function testRequirementsBackend() { - $requirements = new Requirements_Backend(); - $requirements->javascript(SAPPHIRE_DIR . '/tests/forms/a.js'); + $backend = new Requirements_Backend(); + $backend->javascript(SAPPHIRE_DIR . '/tests/forms/a.js'); - $this->assertTrue(count($requirements->get_javascript()) == 1, "There should be only 1 file included in required javascript."); - $this->assertTrue(in_array(SAPPHIRE_DIR . '/tests/forms/a.js', $requirements->get_javascript()), "/test/forms/a.js should be included in required javascript."); + $this->assertTrue(count($backend->get_javascript()) == 1, "There should be only 1 file included in required javascript."); + $this->assertTrue(in_array(SAPPHIRE_DIR . '/tests/forms/a.js', $backend->get_javascript()), "/test/forms/a.js should be included in required javascript."); - $requirements->javascript(SAPPHIRE_DIR . '/tests/forms/b.js'); - $this->assertTrue(count($requirements->get_javascript()) == 2, "There should be 2 files included in required javascript."); + $backend->javascript(SAPPHIRE_DIR . '/tests/forms/b.js'); + $this->assertTrue(count($backend->get_javascript()) == 2, "There should be 2 files included in required javascript."); - $requirements->block(SAPPHIRE_DIR . '/tests/forms/a.js'); - $this->assertTrue(count($requirements->get_javascript()) == 1, "There should be only 1 file included in required javascript."); - $this->assertFalse(in_array(SAPPHIRE_DIR . '/tests/forms/a.js', $requirements->get_javascript()), "/test/forms/a.js should not be included in required javascript after it has been blocked."); - $this->assertTrue(in_array(SAPPHIRE_DIR . '/tests/forms/b.js', $requirements->get_javascript()), "/test/forms/b.js should be included in required javascript."); + $backend->block(SAPPHIRE_DIR . '/tests/forms/a.js'); + $this->assertTrue(count($backend->get_javascript()) == 1, "There should be only 1 file included in required javascript."); + $this->assertFalse(in_array(SAPPHIRE_DIR . '/tests/forms/a.js', $backend->get_javascript()), "/test/forms/a.js should not be included in required javascript after it has been blocked."); + $this->assertTrue(in_array(SAPPHIRE_DIR . '/tests/forms/b.js', $backend->get_javascript()), "/test/forms/b.js should be included in required javascript."); - $requirements->css(SAPPHIRE_DIR . '/tests/forms/a.css'); - $this->assertTrue(count($requirements->get_css()) == 1, "There should be only 1 file included in required css."); - $this->assertArrayHasKey(SAPPHIRE_DIR . '/tests/forms/a.css', $requirements->get_css(), "/tests/forms/a.css should be in required css."); + $backend->css(SAPPHIRE_DIR . '/tests/forms/a.css'); + $this->assertTrue(count($backend->get_css()) == 1, "There should be only 1 file included in required css."); + $this->assertArrayHasKey(SAPPHIRE_DIR . '/tests/forms/a.css', $backend->get_css(), "/tests/forms/a.css should be in required css."); - $requirements->block(SAPPHIRE_DIR . '/tests/forms/a.css'); - $this->assertTrue(count($requirements->get_css()) == 0, "There should be nothing in required css after file has been blocked."); + $backend->block(SAPPHIRE_DIR . '/tests/forms/a.css'); + $this->assertTrue(count($backend->get_css()) == 0, "There should be nothing in required css after file has been blocked.");