Skip to content
This repository
Browse code

Moving private method detection into Controller.

This fixes an issue where potected methods would
not be called, and no exception would be raised.
  • Loading branch information...
commit 177cd39abb26686cc8fe73292e89ed735079a9fb 1 parent 8bfc0a8
Mark Story authored July 09, 2011 markstory committed July 22, 2011
55  lib/Cake/Controller/Controller.php
@@ -443,6 +443,61 @@ public function setRequest(CakeRequest $request) {
443 443
 	}
444 444
 
445 445
 /**
  446
+ * Dispatches the controller action.  Checks that the action 
  447
+ * exists and isn't private.
  448
+ *
  449
+ * @param CakeRequest $request
  450
+ * @return The resulting response.
  451
+ */
  452
+	public function invokeAction(CakeRequest $request) {
  453
+		$reflection = new ReflectionClass($this);
  454
+		try {
  455
+			$method = $reflection->getMethod($request->params['action']);
  456
+
  457
+			if ($this->_isPrivateAction($method, $request)) {
  458
+				throw new PrivateActionException(array(
  459
+					'controller' => $this->name . "Controller",
  460
+					'action' => $request->params['action']
  461
+				));
  462
+			}
  463
+			return $method->invokeArgs($this, $request->params['pass']);
  464
+
  465
+		} catch (ReflectionException $e) {
  466
+			if ($this->scaffold !== false) {
  467
+				return new Scaffold($this, $request);
  468
+			}
  469
+			throw new MissingActionException(array(
  470
+				'controller' => $this->name . "Controller",
  471
+				'action' => $request->params['action']
  472
+			));
  473
+		}
  474
+	}
  475
+
  476
+/**
  477
+ * Check if the request's action is marked as private, with an underscore, of if the request is attempting to
  478
+ * directly accessing a prefixed action.
  479
+ *
  480
+ * @param ReflectionMethod $method The method to be invoked.
  481
+ * @param CakeRequest $request The request to check.
  482
+ * @return boolean
  483
+ */
  484
+	protected function _isPrivateAction(ReflectionMethod $method, CakeRequest $request) {
  485
+		$privateAction = (
  486
+			$method->name[0] === '_' || 
  487
+			!$method->isPublic() ||
  488
+			!in_array($method->name,  $this->methods)
  489
+		);
  490
+		$prefixes = Router::prefixes();
  491
+
  492
+		if (!$privateAction && !empty($prefixes)) {
  493
+			if (empty($request->params['prefix']) && strpos($request->params['action'], '_') > 0) {
  494
+				list($prefix, $action) = explode('_', $request->params['action']);
  495
+				$privateAction = in_array($prefix, $prefixes);
  496
+			}
  497
+		}
  498
+		return $privateAction;
  499
+	}
  500
+/**
446 501
  * Merge components, helpers, and uses vars from Controller::$_mergeParent and PluginAppController.
447 502
  *
448 503
  * @return void
43  lib/Cake/Routing/Dispatcher.php
@@ -93,38 +93,10 @@ public function dispatch(CakeRequest $request, CakeResponse $response, $addition
93 93
 			));
94 94
 		}
95 95
 
96  
-		if ($this->_isPrivateAction($request)) {
97  
-			throw new PrivateActionException(array(
98  
-				'controller' => Inflector::camelize($request->params['controller']) . "Controller",
99  
-				'action' => $request->params['action']
100  
-			));
101  
-		}
102  
-
103 96
 		return $this->_invoke($controller, $request, $response);
104 97
 	}
105 98
 
106 99
 /**
107  
- * Check if the request's action is marked as private, with an underscore, of if the request is attempting to
108  
- * directly accessing a prefixed action.
109  
- *
110  
- * @param CakeRequest $request The request to check
111  
- * @return boolean
112  
- */
113  
-	protected function _isPrivateAction($request) {
114  
-		$privateAction = $request->params['action'][0] === '_';
115  
-		$prefixes = Router::prefixes();
116  
-
117  
-		if (!$privateAction && !empty($prefixes)) {
118  
-			if (empty($request->params['prefix']) && strpos($request->params['action'], '_') > 0) {
119  
-				list($prefix, $action) = explode('_', $request->params['action']);
120  
-				$privateAction = in_array($prefix, $prefixes);
121  
-			}
122  
-		}
123  
-
124  
-		return $privateAction;
125  
-	}
126  
-
127  
-/**
128 100
  * Initializes the components and models a controller will be using.
129 101
  * Triggers the controller action, and invokes the rendering if Controller::$autoRender is true and echo's the output.
130 102
  * Otherwise the return value of the controller action are returned.
@@ -138,22 +110,11 @@ protected function _invoke(Controller $controller, CakeRequest $request, CakeRes
138 110
 		$controller->constructClasses();
139 111
 		$controller->startupProcess();
140 112
 
141  
-		$methods = array_flip($controller->methods);
142  
-
143  
-		if (!isset($methods[$request->params['action']])) {
144  
-			if ($controller->scaffold !== false) {
145  
-				return new Scaffold($controller, $request);
146  
-			}
147  
-			throw new MissingActionException(array(
148  
-				'controller' => Inflector::camelize($request->params['controller']) . "Controller",
149  
-				'action' => $request->params['action']
150  
-			));
151  
-		}
152  
-		$result = call_user_func_array(array(&$controller, $request->params['action']), $request->params['pass']);
153  
-
  113
+		$result = $controller->invokeAction($request);
154 114
 		if ($result instanceof CakeResponse) {
155 115
 			$response = $result;
156 116
 		}
  117
+		
157 118
 		if ($controller->autoRender) {
158 119
 			$response = $controller->render();
159 120
 		} elseif ($response->body() === null) {
14  lib/Cake/Test/Case/Routing/DispatcherTest.php
@@ -50,11 +50,7 @@ class TestDispatcher extends Dispatcher {
50 50
  * @return void
51 51
  */
52 52
 	protected function _invoke(Controller $controller, CakeRequest $request, CakeResponse $response) {
53  
-		if ($result = parent::_invoke($controller, $request, $response)) {
54  
-			if ($result[0] === 'missingAction') {
55  
-				return $result;
56  
-			}
57  
-		}
  53
+		$result = parent::_invoke($controller, $request, $response);
58 54
 		return $controller;
59 55
 	}
60 56
 
@@ -733,13 +729,13 @@ public function testMissingAction() {
733 729
 	}
734 730
 
735 731
 /**
736  
- * test that methods declared in Controller are treated as missing methods.
  732
+ * test that methods declared in Controller are treated as private methods.
737 733
  *
738  
- * @expectedException MissingActionException
739  
- * @expectedExceptionMessage Action SomePagesController::redirect() could not be found.
  734
+ * @expectedException PrivateActionException
  735
+ * @expectedExceptionMessage Private Action SomePagesController::redirect() is not directly accessible.
740 736
  * @return void
741 737
  */
742  
-	public function testMissingActionFromBaseClassMethods() {
  738
+	public function testPrivateActionFromBaseClassMethods() {
743 739
 		$Dispatcher = new TestDispatcher();
744 740
 		Configure::write('App.baseUrl','/index.php');
745 741
 		$url = new CakeRequest('some_pages/redirect/param:value/param2:value2');

0 notes on commit 177cd39

Please sign in to comment.
Something went wrong with that request. Please try again.