Permalink
Browse files

ENHANCEMENT FieldList->setTabPathRewrites() for better backwards comp…

…atibility (see #7261)
  • Loading branch information...
1 parent f546ab2 commit 8c9560d2880be25aceb06982b0f30d4101cf5b8a @chillu chillu committed May 9, 2012
Showing with 124 additions and 0 deletions.
  1. +63 −0 forms/FieldList.php
  2. +61 −0 tests/forms/FieldListTest.php
View
@@ -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) {
@@ -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.
@@ -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;
@@ -556,6 +566,59 @@ public function fieldPosition($field) {
}
/**
+ * 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.
*/
function forTemplate() {
@@ -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.