Skip to content

Commit

Permalink
ENHANCEMENT FieldList->setTabPathRewrites() for better backwards comp…
Browse files Browse the repository at this point in the history
…atibility (see #7261)
  • Loading branch information
chillu committed May 9, 2012
1 parent f546ab2 commit 8c9560d
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 0 deletions.
63 changes: 63 additions & 0 deletions forms/FieldList.php
Expand Up @@ -25,6 +25,12 @@ class FieldList extends ArrayList {
* @todo Documentation
*/
protected $containerField;

/**
* @var array Ordered list of regular expressions,
* see {@link setTabPathRewrites()}.
*/
protected $tabPathRewrites = array();

public function __construct($items = array()) {
if (!is_array($items) || func_num_args() > 1) {
Expand Down Expand Up @@ -255,6 +261,9 @@ public function hasTabSet() {
* @return Tab The found or newly created Tab instance
*/
public function findOrMakeTab($tabName, $title = null) {
// Backwards compatibility measure: Allow rewriting of outdated tab paths
$tabName = $this->rewriteTabPath($tabName);

$parts = explode('.',$tabName);
$last_idx = count($parts) - 1;
// We could have made this recursive, but I've chosen to keep all the logic code within FieldList rather than add it to TabSet and Tab too.
Expand Down Expand Up @@ -291,6 +300,7 @@ public function findOrMakeTab($tabName, $title = null) {
* @todo Implement similiarly to dataFieldByName() to support nested sets - or merge with dataFields()
*/
public function fieldByName($name) {
$name = $this->rewriteTabPath($name);
if(strpos($name,'.') !== false) list($name, $remainder) = explode('.',$name,2);
else $remainder = null;

Expand Down Expand Up @@ -555,6 +565,59 @@ public function fieldPosition($field) {
return false;
}

/**
* Ordered list of regular expressions
* matching a tab path, to their rewrite rule (through preg_replace()).
* Mainly used for backwards compatibility.
* Ensure that more specific rules are placed earlier in the list,
* and that tabs with children are accounted for in the rule sets.
*
* Example:
* $fields->setTabPathRewriting(array(
* // Rewrite specific innermost tab
* '/^Root\.Content\.Main$/' => 'Root.Content',
* // Rewrite all innermost tabs
* '/^Root\.Content\.([^.]+)$/' => 'Root.\\1',
* ));
*
* @param array $rewrites
*/
public function setTabPathRewrites($rewrites) {
$this->tabPathRewrites = $rewrites;
}

/**
* @return array
*/
public function getTabPathRewrites() {
return $this->tabPathRewrites;
}

/**
* Support function for backwards compatibility purposes.
* Caution: Volatile API, might be removed in 3.1 or later.
*
* @param String $tabname Path to a tab, e.g. "Root.Content.Main"
* @return String Rewritten path, based on {@link tabPathRewrites}
*/
protected function rewriteTabPath($name) {
$isRunningTest = (class_exists('SapphireTest', false) && SapphireTest::is_running_test());
foreach($this->getTabPathRewrites() as $regex => $replace) {
if(preg_match($regex, $name)) {
$newName = preg_replace($regex, $replace, $name);
Deprecation::notice('3.0.0', sprintf(
'Using outdated tab path "%s", please use the new location "%s" instead',
$name,
$newName
));
return $newName;
}
}

// No match found, return original path
return $name;
}

/**
* Default template rendering of a FieldList will concatenate all FieldHolder values.
*/
Expand Down
61 changes: 61 additions & 0 deletions tests/forms/FieldListTest.php
Expand Up @@ -789,5 +789,66 @@ function testVisibleAndHiddenFields() {
$this->assertNotNull($visible->dataFieldByName('D2'));
}

function testRewriteTabPath() {
$fields = new FieldList(
new Tabset("Root",
$tab1Level1 = new Tab("Tab1Level1",
$tab1Level2 = new Tab("Tab1Level2"),
$tab2Level2 = new Tab("Tab2Level2")
),
$tab2Level1 = new Tab("Tab2Level1")
)
);
$fields->setTabPathRewrites(array(
'/Root\.Tab1Level1\.([^.]+)$/' => 'Root.Tab1Level1Renamed.\\1',
'/Root\.Tab1Level1$/' => 'Root.Tab1Level1Renamed',
));
$method = new ReflectionMethod($fields, 'rewriteTabPath');
$method->setAccessible(true);
$this->assertEquals(
'Root.Tab1Level1Renamed',
$method->invoke($fields, 'Root.Tab1Level1Renamed'),
"Doesn't rewrite new name"
);
$this->assertEquals(
'Root.Tab1Level1Renamed',
$method->invoke($fields, 'Root.Tab1Level1'),
'Direct aliasing on toplevel'
);
$this->assertEquals(
'Root.Tab1Level1Renamed.Tab1Level2',
$method->invoke($fields, 'Root.Tab1Level1.Tab1Level2'),
'Indirect aliasing on toplevel'
);
}

function testRewriteTabPathFindOrMakeTab() {
$fields = new FieldList(
new Tabset("Root",
$tab1Level1 = new Tab("Tab1Level1Renamed",
$tab1Level2 = new Tab("Tab1Level2"),
$tab2Level2 = new Tab("Tab2Level2")
),
$tab2Level1 = new Tab("Tab2Level1")
)
);
$fields->setTabPathRewrites(array(
'/Root\.Tab1Level1\.([^.]+)$/' => 'Root.Tab1Level1Renamed.\\1',
'/Root\.Tab1Level1$/' => 'Root.Tab1Level1Renamed',
));

$this->assertEquals($tab1Level1, $fields->findOrMakeTab('Root.Tab1Level1'),
'findOrMakeTab() with toplevel tab under old name'
);
$this->assertEquals($tab1Level1, $fields->findOrMakeTab('Root.Tab1Level1Renamed'),
'findOrMakeTab() with toplevel tab under new name'
);
$this->assertEquals($tab1Level2, $fields->findOrMakeTab('Root.Tab1Level1.Tab1Level2'),
'findOrMakeTab() with nested tab under old parent tab name'
);
$this->assertEquals($tab1Level2, $fields->findOrMakeTab('Root.Tab1Level1Renamed.Tab1Level2'),
'findOrMakeTab() with nested tab under new parent tab name'
);
}

}

0 comments on commit 8c9560d

Please sign in to comment.