Silverstripe:无法使用自定义路径访问控制器中的页面字段

I'm using SilverStripe 3.3.1 and have a custom route set up to handle urls with many parameters. That works.

However, the routing rule causes Page fields and functions to be inaccessible in the Page_Controller and templates. Any ideas how to fix this?

//MyPage class
class MyPage extends Page {

    //Not accessible if route to controller specified in config.yml
    private static $db = array(
        'MyPageVar' => 'Int',
    );

     //Not accessible if route to controller specified in config.yml
     public function getMySpecialVar() {
         return $this->MyPageVar;
     } 
}

//MyPage_Controller class
class MyPage_Controller extends Page_Controller {

    private static $allowed_actions = array(
        'index',
        'detailsearch',
    );

    private static $url_handlers = array (
        'detailsearch/$Key1/$Value1/$Key2/$Value2/$Key3/$Value3/$Key4/$Value4/$Key5/$Value5' => 'detailsearch',
    );


    /**
     * UseMyPageVar() 
     * 
     * @return Boolean
     */
    public function UseMyPageVar() {
        //Empty if route to controller specified in config.yml
        Debug::show($this->MyPageVar);
        Debug::show($this->Title);
        Debug::show($this->Content);
        //Error if route to controller specified in config.yml
        Debug::show($this->getMySpecialVar());

        return true;
    }
}

MyPage.ss

<!-- This work as expected if no route is specified. -->
<!-- But all vars are empty if route is specified in config.yml -->
<p>MyVar: $MyPageVar</p>
<p>Title: $Title</p>
<p>Content: $Content</p>

Routing rule in config.yml

Director:
  rules:
    'mypage': 'MyPage_Controller'

This question is also posted on the Silverstripe forum: http://www.silverstripe.org/community/forums/general-questions/editpost/413506

It's not pretty, but for now I've solved the problem by using a private var in the Controller class to hold a reference to the page.

//MyPage_Controller class
class MyPage_Controller extends Page_Controller {

    private $_page; //reference to page that's lost with custom routing        

    //ContentController uses route, which has been changed to
    //   'MyPage_Controller' by routing rule, to initialize 
    //   page reference. Can't find anything so reference
    //   not set. (set to -1)
    public function init() {
        parent::init();

        //Initialize using default route overwritten in routing rule
        //    This will break if URL segment changed in CMS  
        $route = array_search($this->URLSegment,
                        Config::inst()->get('Director', 'rules'));
        $link = str_replace($this->URLSegment, $route, $this->Link());
        $this->_page = $this->Page($link);
    }


    //Use private var to access page fields 
    public function MyPageVar() {  
        Debug::show($this->_page->MyPageVar);
    }

    //expose $Content to templates
    public function Content() {
        return $this->_page->Content;
    }

    //Can't use Title() so expose Page Title as $PageTitle
    public function PageTitle() {
        return $this->_page->Title;
    }
}

Three things spring to mind when I look at your code:

  1. That "mypage" in config.yml should be the name of a public method on MyPage_Controller. As it is, SilverStripe cannot find a matching method called mypage and will default to calling index() instead.

  2. Routes should really go in a separate routes.yml file so you can "namespace" it to be invoked before or after SilverStripe's own core routes. If you don't do this, then it may result in the weird behaviour you're experiencing.

  3. Did you know that you can debug your routes using the ?debug_request=1 URL param? See: https://docs.silverstripe.org/en/3.3/developer_guides/debugging/url_variable_tools#general-testing