From 3d827543a8d7d419bba5ac79d398614f31b296a7 Mon Sep 17 00:00:00 2001 From: Loz Calver Date: Thu, 8 Sep 2016 15:46:48 +0100 Subject: [PATCH 1/2] NEW: Allow pages to specify the controller they use --- code/Controllers/ModelAsController.php | 18 +++--------------- code/Model/SiteTree.php | 20 ++++++++++++++++++++ 2 files changed, 23 insertions(+), 15 deletions(-) diff --git a/code/Controllers/ModelAsController.php b/code/Controllers/ModelAsController.php index ee5409b5..7984a8b2 100644 --- a/code/Controllers/ModelAsController.php +++ b/code/Controllers/ModelAsController.php @@ -37,25 +37,13 @@ class ModelAsController extends Controller implements NestedController { * @return ContentController */ public static function controller_for(SiteTree $sitetree, $action = null) { - if ($sitetree->class == 'SilverStripe\\CMS\\Model\\SiteTree') { - $controller = "SilverStripe\\CMS\\Controllers\\ContentController"; - } else { - $ancestry = ClassInfo::ancestry($sitetree->class); - while ($class = array_pop($ancestry)) { - if (class_exists($class . "_Controller")) { - break; - } - } - $controller = ($class !== null) - ? "{$class}_Controller" - : "SilverStripe\\CMS\\Controllers\\ContentController"; - } + $controller = $sitetree->getControllerName(); - if($action && class_exists($controller . '_' . ucfirst($action))) { + if ($action && class_exists($controller . '_' . ucfirst($action))) { $controller = $controller . '_' . ucfirst($action); } - return class_exists($controller) ? Injector::inst()->create($controller, $sitetree) : $sitetree; + return Injector::inst()->create($controller, $sitetree); } public function init() { diff --git a/code/Model/SiteTree.php b/code/Model/SiteTree.php index 175ae86e..010ee8cb 100755 --- a/code/Model/SiteTree.php +++ b/code/Model/SiteTree.php @@ -2712,6 +2712,26 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid return 1; } + /** + * @return string + */ + public function getControllerName() { + if ($this->class === SiteTree::class) { + $controller = ContentController::class; + } else { + $ancestry = ClassInfo::ancestry($this->class); + while ($class = array_pop($ancestry)) { + if (class_exists($class . "_Controller")) { + break; + } + } + + $controller = ($class !== null) ? "{$class}_Controller" : ContentController::class; + } + + return $controller; + } + /** * Return the CSS classes to apply to this node in the CMS tree. * From 62816e1ff8cb2e8307859853fbc1a26a7e6470e8 Mon Sep 17 00:00:00 2001 From: Loz Calver Date: Thu, 8 Sep 2016 15:47:03 +0100 Subject: [PATCH 2/2] Refactor VirtualPage, remove VirtualPage_Controller --- code/Model/VirtualPage.php | 42 +++++---- code/Model/VirtualPage_Controller.php | 117 -------------------------- tests/model/VirtualPageTest.php | 17 ++-- 3 files changed, 35 insertions(+), 141 deletions(-) delete mode 100644 code/Model/VirtualPage_Controller.php diff --git a/code/Model/VirtualPage.php b/code/Model/VirtualPage.php index f291647b..a22da5d9 100644 --- a/code/Model/VirtualPage.php +++ b/code/Model/VirtualPage.php @@ -414,24 +414,6 @@ class VirtualPage extends Page { return $copy && $copy->exists() && $copy->hasField($field); } - /** - * Overwrite to also check for method on the original data object - * - * @param string $method - * @return bool - */ - public function hasMethod($method) { - if(parent::hasMethod($method)) { - return true; - } - // Don't call property setters on copied page - if(stripos($method, 'set') === 0) { - return false; - } - $copy = $this->CopyContentFrom(); - return $copy && $copy->exists() && $copy->hasMethod($method); - } - /** * Return the "casting helper" (a piece of PHP code that when evaluated creates a casted value object) for a field * on this object. @@ -447,4 +429,28 @@ class VirtualPage extends Page { return parent::castingHelper($field); } + /** + * {@inheritdoc} + */ + public function allMethodNames($custom = false) { + $methods = parent::allMethodNames($custom); + + if ($copy = $this->CopyContentFrom()) { + $methods = array_merge($methods, $copy->allMethodNames($custom)); + } + + return $methods; + } + + /** + * {@inheritdoc} + */ + public function getControllerName() { + if ($copy = $this->CopyContentFrom()) { + return $copy->getControllerName(); + } + + return parent::getControllerName(); + } + } diff --git a/code/Model/VirtualPage_Controller.php b/code/Model/VirtualPage_Controller.php deleted file mode 100644 index fc13b597..00000000 --- a/code/Model/VirtualPage_Controller.php +++ /dev/null @@ -1,117 +0,0 @@ - 'ADMIN', - ); - - /** - * Backup of virtualised controller - * - * @var ContentController - */ - protected $virtualController = null; - - /** - * Get virtual controller - * - * @return ContentController - */ - protected function getVirtualisedController() - { - if ($this->virtualController) { - return $this->virtualController; - } - - // Validate virtualised model - /** @var VirtualPage $page */ - $page = $this->data(); - $virtualisedPage = $page->CopyContentFrom(); - if (!$virtualisedPage || !$virtualisedPage->exists()) { - return null; - } - - // Create controller using standard mechanism - $this->virtualController = ModelAsController::controller_for($virtualisedPage); - return $this->virtualController; - } - - public function getViewer($action) - { - $controller = $this->getVirtualisedController(); - if($controller) { - return $controller->getViewer($action); - } - return parent::getViewer($action); - } - - /** - * When the virtualpage is loaded, check to see if the versions are the same - * if not, reload the content. - * NOTE: Virtual page must have a container object of subclass of sitetree. - * We can't load the content without an ID or record to copy it from. - */ - public function init() - { - parent::init(); - $this->__call('init', array()); - } - - /** - * Also check the original object's original controller for the method - * - * @param string $method - * @return bool - */ - public function hasMethod($method) - { - if (parent::hasMethod($method)) { - return true; - }; - - // Fallback - $controller = $this->getVirtualisedController(); - return $controller && $controller->hasMethod($method); - } - - /** - * Pass unrecognized method calls on to the original controller - * - * @param string $method - * @param string $args - * @return mixed - * - * @throws Exception Any error other than a 'no method' error. - */ - public function __call($method, $args) - { - // Check if we can safely call this method before passing it back - // to custom methods. - if ($this->getExtraMethodConfig($method)) { - return parent::__call($method, $args); - } - - // Pass back to copied page - $controller = $this->getVirtualisedController(); - if (!$controller) { - return null; - } - - // Ensure request/response data is available on virtual controller - $controller->setRequest($this->getRequest()); - $controller->setResponse($this->getResponse()); - - return call_user_func_array(array($controller, $method), $args); - } -} diff --git a/tests/model/VirtualPageTest.php b/tests/model/VirtualPageTest.php index d59d6515..3e69aaf5 100644 --- a/tests/model/VirtualPageTest.php +++ b/tests/model/VirtualPageTest.php @@ -1,6 +1,5 @@ objFromFixture('SilverStripe\\CMS\\Model\\VirtualPage', 'vp4'); $controller = ModelAsController::controller_for($virtualPage); - $this->assertInstanceOf('SilverStripe\\CMS\\Model\\VirtualPage_Controller', $controller); + $this->assertInstanceOf('VirtualPageTest_ClassA_Controller', $controller); $this->assertTrue($controller->hasMethod('testMethod')); $this->assertEquals('hello', $controller->testMethod()); $this->assertTrue($controller->hasMethod('modelMethod')); $this->assertEquals('hi there', $controller->modelMethod()); } + + public function testAllowedActions() { + $virtualPage = $this->objFromFixture('SilverStripe\\CMS\\Model\\VirtualPage', 'vp4'); + $controller = ModelAsController::controller_for($virtualPage); + $this->assertContains('testaction', $controller->allowedActions()); + } } class VirtualPageTest_ClassA extends Page implements TestOnly { @@ -641,6 +642,10 @@ class VirtualPageTest_ClassA extends Page implements TestOnly { } class VirtualPageTest_ClassA_Controller extends Page_Controller implements TestOnly { + private static $allowed_actions = [ + 'testaction' + ]; + public function testMethod() { return 'hello'; }