mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
Merge branch '3.1'
This commit is contained in:
commit
8a62593754
@ -973,7 +973,7 @@ class LeftAndMain extends Controller implements PermissionProvider {
|
||||
if(substr($SQL_id,0,3) != 'new') {
|
||||
$record = DataObject::get_by_id($className, $SQL_id);
|
||||
if($record && !$record->canEdit()) return Security::permissionFailure($this);
|
||||
if(!$record || !$record->ID) throw new HTTPResponse_Exception("Bad record ID #" . (int)$data['ID'], 404);
|
||||
if(!$record || !$record->ID) $this->httpError(404, "Bad record ID #" . (int)$data['ID']);
|
||||
} else {
|
||||
if(!singleton($this->stat('tree_class'))->canCreate()) return Security::permissionFailure($this);
|
||||
$record = $this->getNewItem($SQL_id, false);
|
||||
@ -994,7 +994,7 @@ class LeftAndMain extends Controller implements PermissionProvider {
|
||||
|
||||
$record = DataObject::get_by_id($className, Convert::raw2sql($data['ID']));
|
||||
if($record && !$record->canDelete()) return Security::permissionFailure();
|
||||
if(!$record || !$record->ID) throw new HTTPResponse_Exception("Bad record ID #" . (int)$data['ID'], 404);
|
||||
if(!$record || !$record->ID) $this->httpError(404, "Bad record ID #" . (int)$data['ID']);
|
||||
|
||||
$record->delete();
|
||||
|
||||
|
@ -23,7 +23,7 @@ class SS_ConfigManifest {
|
||||
* the current environment.
|
||||
* @var array
|
||||
*/
|
||||
protected $variantKeySpec = array();
|
||||
protected $variantKeySpec = false;
|
||||
|
||||
/**
|
||||
* All the _config.php files. Need to be included every request & can't be cached. Not variant specific.
|
||||
@ -88,10 +88,7 @@ class SS_ConfigManifest {
|
||||
$this->includeTests = $includeTests;
|
||||
|
||||
// Get the Zend Cache to load/store cache into
|
||||
$this->cache = SS_Cache::factory('SS_Configuration', 'Core', array(
|
||||
'automatic_serialization' => true,
|
||||
'lifetime' => null
|
||||
));
|
||||
$this->cache = $this->getCache();
|
||||
|
||||
// Unless we're forcing regen, try loading from cache
|
||||
if (!$forceRegen) {
|
||||
@ -102,7 +99,7 @@ class SS_ConfigManifest {
|
||||
}
|
||||
|
||||
// If we don't have a variantKeySpec (because we're forcing regen, or it just wasn't in the cache), generate it
|
||||
if (!$this->variantKeySpec) {
|
||||
if (false === $this->variantKeySpec) {
|
||||
$this->regenerate($includeTests);
|
||||
}
|
||||
|
||||
@ -110,6 +107,18 @@ class SS_ConfigManifest {
|
||||
$this->buildYamlConfigVariant();
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a hook for mock unit tests despite no DI
|
||||
* @return Zend_Cache_Frontend
|
||||
*/
|
||||
protected function getCache()
|
||||
{
|
||||
return SS_Cache::factory('SS_Configuration', 'Core', array(
|
||||
'automatic_serialization' => true,
|
||||
'lifetime' => null
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a callback to be called whenever the calculated merged config changes
|
||||
*
|
||||
|
@ -6,8 +6,8 @@ The CMS interface works just like any other part of your website: It consists of
|
||||
PHP controllers, templates, CSS stylesheets and JavaScript. Because it uses the
|
||||
same base elements, it is relatively easy to extend.
|
||||
|
||||
As an example, we're going to add a permanent "bookmarks" bar to popular pages
|
||||
at the bottom of the CMS. A page can be bookmarked by a CMS author through a
|
||||
As an example, we're going to add a permanent "bookmarks" link list to popular pages
|
||||
into the main CMS menu. A page can be bookmarked by a CMS author through a
|
||||
simple checkbox.
|
||||
|
||||
For a deeper introduction to the inner workings of the CMS, please refer to our
|
||||
@ -24,48 +24,35 @@ the common `Page` object (a new PHP class `MyPage` will look for a `MyPage.ss` t
|
||||
We can use this to create a different base template with `LeftAndMain.ss`
|
||||
(which corresponds to the `LeftAndMain` PHP controller class).
|
||||
|
||||
Copy the template markup of the base implementation at `framework/admin/templates/LeftAndMain.ss`
|
||||
into `mysite/templates/LeftAndMain.ss`. It will automatically be picked up by
|
||||
the CMS logic. Add a new section after the `$Content` tag:
|
||||
Copy the template markup of the base implementation at `framework/admin/templates/Includes/LeftAndMain_Menu.ss`
|
||||
into `mysite/templates/Includes/LeftAndMain_Menu.ss`. It will automatically be picked up by
|
||||
the CMS logic. Add a new section into the `<ul class="cms-menu-list">`
|
||||
|
||||
:::ss
|
||||
...
|
||||
<div class="cms-container" data-layout-type="border">
|
||||
$Menu
|
||||
$Content
|
||||
<div class="cms-bottom-bar south">
|
||||
<ul>
|
||||
<li><a href="admin/page/edit/show/1">Edit "My popular page"</a></li>
|
||||
<li><a href="admin/page/edit/show/99">Edit "My other page"</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<ul class="cms-menu-list">
|
||||
<!-- ... -->
|
||||
<li class="bookmarked-link first">
|
||||
<a href="admin/pages/edit/show/1">Edit "My popular page"</a>
|
||||
</li>
|
||||
<li class="bookmarked-link last">
|
||||
<a href="admin/pages/edit/show/99">Edit "My other page"</a>
|
||||
</li>
|
||||
</ul>
|
||||
...
|
||||
|
||||
Refresh the CMS interface with `admin/?flush=all`, and you should see the new
|
||||
bottom bar with some hardcoded links. We'll make these dynamic further down.
|
||||
Refresh the CMS interface with `admin/?flush=all`, and you should see those
|
||||
hardcoded links underneath the left-hand menu. We'll make these dynamic further down.
|
||||
|
||||
You might have noticed that we didn't write any JavaScript to add our layout
|
||||
manager. The important piece of information is the `south` class in our new
|
||||
`<div>` structure, plus the height value in our CSS. It instructs the existing
|
||||
parent layout how to render the element. This layout manager
|
||||
([jLayout](http://www.bramstein.com/projects/jlayout/)) allows us to build
|
||||
complex layouts with minimal JavaScript configuration.
|
||||
|
||||
See [layout reference](../reference/layout) for more specific information on
|
||||
CMS layouting.
|
||||
|
||||
## Include custom CSS in the CMS
|
||||
|
||||
In order to show the links in one line, we'll add some CSS, and get it to load
|
||||
In order to show the links a bit separated from the other menu entries,
|
||||
we'll add some CSS, and get it to load
|
||||
with the CMS interface. Paste the following content into a new file called
|
||||
`mysite/css/BookmarkedPages.css`:
|
||||
|
||||
:::css
|
||||
.cms-bottom-bar {height: 20px; padding: 5px; background: #C6D7DF;}
|
||||
.cms-bottom-bar ul {list-style: none; margin: 0; padding: 0;}
|
||||
.cms-bottom-bar ul li {float: left; margin-left: 1em;}
|
||||
.cms-bottom-bar a {color: #444444;}
|
||||
.bookmarked-link.first {margin-top: 1em;}
|
||||
|
||||
Load the new CSS file into the CMS, by setting the `LeftAndMain.extra_requirements_css`
|
||||
[configuration value](/topics/configuration).
|
||||
@ -139,9 +126,12 @@ Find the `<ul>` you created earlier in `mysite/admin/templates/LeftAndMain.ss`
|
||||
and replace it with the following:
|
||||
|
||||
:::ss
|
||||
<ul>
|
||||
<ul class="cms-menu-list">
|
||||
<!-- ... -->
|
||||
<% loop $BookmarkedPages %>
|
||||
<li><a href="admin/pages/edit/show/$ID">Edit "$Title"</a></li>
|
||||
<li class="bookmarked-link $FirstLast">
|
||||
<li><a href="admin/pages/edit/show/$ID">Edit "$Title"</a></li>
|
||||
</li>
|
||||
<% end_loop %>
|
||||
</ul>
|
||||
|
||||
|
@ -8,6 +8,11 @@ class ConfigManifestTest_ConfigManifestAccess extends SS_ConfigManifest {
|
||||
|
||||
class ConfigManifestTest extends SapphireTest {
|
||||
|
||||
/**
|
||||
* This is a helper method for getting a new manifest
|
||||
* @param $name
|
||||
* @return any
|
||||
*/
|
||||
protected function getConfigFixtureValue($name) {
|
||||
$manifest = new SS_ConfigManifest(dirname(__FILE__).'/fixtures/configmanifest', true, true);
|
||||
return $manifest->get('ConfigManifestTest', $name);
|
||||
@ -20,16 +25,140 @@ class ConfigManifestTest extends SapphireTest {
|
||||
return sprintf('Reference path "%s" failed to parse correctly', $path);
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper method to return a mock of the cache in order to test expectations and reduce dependency
|
||||
* @return Zend_Cache_Core
|
||||
*/
|
||||
protected function getCacheMock() {
|
||||
return $this->getMock(
|
||||
'Zend_Cache_Core',
|
||||
array('load', 'save'),
|
||||
array(),
|
||||
'',
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper method to return a mock of the manifest in order to test expectations and reduce dependency
|
||||
* @param $methods
|
||||
* @return SS_ConfigManifest
|
||||
*/
|
||||
protected function getManifestMock($methods) {
|
||||
return $this->getMock(
|
||||
'SS_ConfigManifest',
|
||||
$methods,
|
||||
array(), // no constructor arguments
|
||||
'', // default
|
||||
false // don't call the constructor
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the caching functionality when we are forcing regeneration
|
||||
*
|
||||
* 1. Test that regenerate is called in the default case and that cache->load isn't
|
||||
* 2. Test that save is called correctly after the regeneration
|
||||
*/
|
||||
public function testCachingForceRegeneration() {
|
||||
// Test that regenerate is called correctly.
|
||||
$manifest = $this->getManifestMock(array('getCache', 'regenerate', 'buildYamlConfigVariant'));
|
||||
|
||||
$manifest->expects($this->once()) // regenerate should be called once
|
||||
->method('regenerate')
|
||||
->with($this->equalTo(true)); // includeTests = true
|
||||
|
||||
// Set up a cache where we expect load to never be called
|
||||
$cache = $this->getCacheMock();
|
||||
$cache->expects($this->never())
|
||||
->method('load');
|
||||
|
||||
$manifest->expects($this->any())
|
||||
->method('getCache')
|
||||
->will($this->returnValue($cache));
|
||||
|
||||
$manifest->__construct(dirname(__FILE__).'/fixtures/configmanifest', true, true);
|
||||
|
||||
// Test that save is called correctly
|
||||
$manifest = $this->getManifestMock(array('getCache'));
|
||||
|
||||
$cache = $this->getCacheMock();
|
||||
$cache->expects($this->atLeastOnce())
|
||||
->method('save');
|
||||
|
||||
$manifest->expects($this->any())
|
||||
->method('getCache')
|
||||
->will($this->returnValue($cache));
|
||||
|
||||
$manifest->__construct(dirname(__FILE__).'/fixtures/configmanifest', true, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the caching functionality when we are not forcing regeneration
|
||||
*
|
||||
* 1. Test that load is called
|
||||
* 2. Test the regenerate is called when the cache is unprimed
|
||||
* 3. Test that when there is a value in the cache regenerate isn't called
|
||||
*/
|
||||
public function testCachingNotForceRegeneration() {
|
||||
// Test that load is called
|
||||
$manifest = $this->getManifestMock(array('getCache', 'regenerate', 'buildYamlConfigVariant'));
|
||||
|
||||
// Load should be called twice
|
||||
$cache = $this->getCacheMock();
|
||||
$cache->expects($this->exactly(2))
|
||||
->method('load');
|
||||
|
||||
$manifest->expects($this->any())
|
||||
->method('getCache')
|
||||
->will($this->returnValue($cache));
|
||||
|
||||
$manifest->__construct(dirname(__FILE__).'/fixtures/configmanifest', true, false);
|
||||
|
||||
|
||||
// Now test that regenerate is called because the cache is unprimed
|
||||
$manifest = $this->getManifestMock(array('getCache', 'regenerate', 'buildYamlConfigVariant'));
|
||||
|
||||
$cache = $this->getCacheMock();
|
||||
$cache->expects($this->exactly(2))
|
||||
->method('load')
|
||||
->will($this->onConsecutiveCalls(false, false));
|
||||
|
||||
$manifest->expects($this->any())
|
||||
->method('getCache')
|
||||
->will($this->returnValue($cache));
|
||||
|
||||
$manifest->expects($this->once())
|
||||
->method('regenerate')
|
||||
->with($this->equalTo(false)); //includeTests = false
|
||||
|
||||
$manifest->__construct(dirname(__FILE__).'/fixtures/configmanifest', false, false);
|
||||
|
||||
// Now test that when there is a value in the cache that regenerate isn't called
|
||||
$manifest = $this->getManifestMock(array('getCache', 'regenerate', 'buildYamlConfigVariant'));
|
||||
|
||||
$cache = $this->getCacheMock();
|
||||
$cache->expects($this->exactly(2))
|
||||
->method('load')
|
||||
->will($this->onConsecutiveCalls(array(), array()));
|
||||
|
||||
$manifest->expects($this->any())
|
||||
->method('getCache')
|
||||
->will($this->returnValue($cache));
|
||||
|
||||
$manifest->expects($this->never())
|
||||
->method('regenerate');
|
||||
|
||||
$manifest->__construct(dirname(__FILE__).'/fixtures/configmanifest', false, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* This test checks the processing of before and after reference paths (module-name/filename#fragment)
|
||||
* This method uses fixture/configmanifest/mysite/_config/addyamlconfigfile.yml as a fixture
|
||||
*/
|
||||
public function testAddYAMLConfigFileReferencePathParsing() {
|
||||
// Use a mock to avoid testing unrelated functionality
|
||||
$manifest = $this->getMockBuilder('SS_ConfigManifest')
|
||||
->disableOriginalConstructor()
|
||||
->setMethods(array('addModule'))
|
||||
->getMock();
|
||||
$manifest = $this->getManifestMock(array('addModule'));
|
||||
|
||||
// This tests that the addModule method is called with the correct value
|
||||
$manifest->expects($this->once())
|
||||
|
Loading…
Reference in New Issue
Block a user