Browse Source

Merge pull request #4823 from cakephp/issue-4796

Add Model.initialize event and rework how Component::initialize() works
ADmad 11 years ago
parent
commit
060a41c0f7

+ 22 - 3
src/Controller/Component.php

@@ -23,13 +23,19 @@ use Cake\Log\LogTrait;
  * controller logic that can be composed into a controller. Components also
  * provide request life-cycle callbacks for injecting logic at specific points.
  *
+ * ## Initialize hook
+ *
+ * Like Controller and Table, this class has an initialize() hook that you can use
+ * to add custom 'constructor' logic. It is important to remember that each request
+ * (and sub-request) will only make one instance of any given component.
+ *
  * ## Life cycle callbacks
  *
  * Components can provide several callbacks that are fired at various stages of the request
  * cycle. The available callbacks are:
  *
- * - `initialize(Event $event)`
- *   Called before the controller's beforeFilter method.
+ * - `beforeFilter(Event $event)`
+ *   Called before the controller's beforeFilter method by default.
  * - `startup(Event $event)`
  *   Called after the controller's beforeFilter method, and before the
  *   controller action is called.
@@ -99,6 +105,19 @@ class Component implements EventListener {
 		if (!empty($this->components)) {
 			$this->_componentMap = $registry->normalizeArray($this->components);
 		}
+		$this->initialize($config);
+	}
+
+/**
+ * Constructor hook method.
+ *
+ * Implement this method to avoid having to overwrite
+ * the constructor and call parent.
+ *
+ * @param array $config The configuration array this component is using.
+ * @return void
+ */
+	public function initialize(array $config) {
 	}
 
 /**
@@ -131,7 +150,7 @@ class Component implements EventListener {
  */
 	public function implementedEvents() {
 		$eventMap = [
-			'Controller.initialize' => 'initialize',
+			'Controller.initialize' => 'beforeFilter',
 			'Controller.startup' => 'startup',
 			'Controller.beforeRender' => 'beforeRender',
 			'Controller.beforeRedirect' => 'beforeRedirect',

+ 60 - 44
src/Controller/Component/RequestHandlerComponent.php

@@ -120,10 +120,6 @@ class RequestHandlerComponent extends Component {
 	public function __construct(ComponentRegistry $registry, array $config = array()) {
 		parent::__construct($registry, $config);
 		$this->addInputType('xml', array(array($this, 'convertXml')));
-
-		$Controller = $registry->getController();
-		$this->request = $Controller->request;
-		$this->response = $Controller->response;
 	}
 
 /**
@@ -133,7 +129,6 @@ class RequestHandlerComponent extends Component {
  */
 	public function implementedEvents() {
 		return [
-			'Controller.initialize' => 'initialize',
 			'Controller.startup' => 'startup',
 			'Controller.beforeRender' => 'beforeRender',
 			'Controller.beforeRedirect' => 'beforeRedirect',
@@ -147,24 +142,27 @@ class RequestHandlerComponent extends Component {
  * of an ajax request indicated using the second header based method above, the type must have
  * been configured in {@link Cake\Routing\Router}.
  *
- * @param Event $event The initialize event that was fired.
+ * @param array $config The config data.
  * @return void
  * @see Router::extensions()
  */
-	public function initialize(Event $event) {
-		if (isset($this->request->params['_ext'])) {
-			$this->ext = $this->request->params['_ext'];
+	public function initialize(array $config) {
+		$controller = $this->_registry->getController();
+		$request = $this->request = $controller->request;
+		$response = $this->response = $controller->response;
+
+		if (isset($request->params['_ext'])) {
+			$this->ext = $request->params['_ext'];
 		}
 		if (empty($this->ext) || in_array($this->ext, array('html', 'htm'))) {
-			$this->_setExtension();
+			$this->_setExtension($request, $this->response);
 		}
-		if (empty($this->ext) && $this->request->is('ajax')) {
+		if (empty($this->ext) && $request->is('ajax')) {
 			$this->ext = 'ajax';
 		}
 
-		$classMap = $this->_config['viewClassMap'];
-		if ($classMap) {
-			$this->viewClassMap($classMap);
+		if ($this->_config['viewClassMap']) {
+			$this->viewClassMap($this->_config['viewClassMap']);
 		}
 	}
 
@@ -179,15 +177,17 @@ class RequestHandlerComponent extends Component {
  * If html is one of the preferred types, no content type will be set, this
  * is to avoid issues with browsers that prefer html and several other content types.
  *
+ * @param \Cake\Network\Request $request The request instance.
+ * @param \Cake\Network\Response $response The response instance.
  * @return void
  */
-	protected function _setExtension() {
-		$accept = $this->request->parseAccept();
+	protected function _setExtension($request, $response) {
+		$accept = $request->parseAccept();
 		if (empty($accept)) {
 			return;
 		}
 
-		$accepts = $this->response->mapType($accept);
+		$accepts = $response->mapType($accept);
 		$preferedTypes = current($accepts);
 		if (array_intersect($preferedTypes, array('html', 'xhtml'))) {
 			return;
@@ -267,7 +267,6 @@ class RequestHandlerComponent extends Component {
 
 /**
  * Handles (fakes) redirects for Ajax requests using requestAction()
- * Modifies the $_POST and $_SERVER['REQUEST_METHOD'] to simulate a new GET request.
  *
  * @param Event $event The Controller.beforeRedirect event.
  * @param string|array $url A string or array containing the redirect location
@@ -275,21 +274,24 @@ class RequestHandlerComponent extends Component {
  * @return void
  */
 	public function beforeRedirect(Event $event, $url, Response $response) {
-		if (!$this->request->is('ajax')) {
+		$request = $this->request;
+		if (!$request->is('ajax')) {
 			return;
 		}
 		if (empty($url)) {
 			return;
 		}
-		$_SERVER['REQUEST_METHOD'] = 'GET';
-		foreach ($_POST as $key => $val) {
-			unset($_POST[$key]);
-		}
 		if (is_array($url)) {
 			$url = Router::url($url + array('base' => false));
 		}
 		$controller = $event->subject();
-		$response->body($controller->requestAction($url, array('return', 'bare' => false)));
+		$response->body($controller->requestAction($url, [
+			'return',
+			'bare' => false,
+			'environment' => [
+				'REQUEST_METHOD' => 'GET'
+			]
+		]));
 		$response->send();
 		$response->stop();
 	}
@@ -304,7 +306,9 @@ class RequestHandlerComponent extends Component {
  * @return bool false if the render process should be aborted
  */
 	public function beforeRender(Event $event) {
-		if ($this->_config['checkHttpCache'] && $this->response->checkNotModified($this->request)) {
+		$response = $this->response;
+		$request = $this->request;
+		if ($this->_config['checkHttpCache'] && $response->checkNotModified($request)) {
 			return false;
 		}
 	}
@@ -343,7 +347,8 @@ class RequestHandlerComponent extends Component {
  * @return bool True if user agent is a mobile web browser
  */
 	public function isMobile() {
-		return $this->request->is('mobile') || $this->accepts('wap');
+		$request = $this->request;
+		return $request->is('mobile') || $this->accepts('wap');
 	}
 
 /**
@@ -378,10 +383,12 @@ class RequestHandlerComponent extends Component {
  *   if the client accepts one or more elements in the array.
  */
 	public function accepts($type = null) {
-		$accepted = $this->request->accepts();
+		$request = $this->request;
+		$response = $this->response;
+		$accepted = $request->accepts();
 
 		if (!$type) {
-			return $this->response->mapType($accepted);
+			return $response->mapType($accepted);
 		}
 		if (is_array($type)) {
 			foreach ($type as $t) {
@@ -407,9 +414,10 @@ class RequestHandlerComponent extends Component {
  *   in the request content type will be returned.
  */
 	public function requestedWith($type = null) {
-		if (!$this->request->is('post') &&
-			!$this->request->is('put') &&
-			!$this->request->is('delete')
+		$request = $this->request;
+		if (!$request->is('post') &&
+			!$request->is('put') &&
+			!$request->is('delete')
 		) {
 			return null;
 		}
@@ -422,15 +430,16 @@ class RequestHandlerComponent extends Component {
 			return false;
 		}
 
-		list($contentType) = explode(';', $this->request->env('CONTENT_TYPE'));
+		list($contentType) = explode(';', $request->env('CONTENT_TYPE'));
 		if ($contentType === '') {
-			list($contentType) = explode(';', $this->request->header('CONTENT_TYPE'));
+			list($contentType) = explode(';', $request->header('CONTENT_TYPE'));
 		}
+		$response = $this->response;
 		if (!$type) {
-			return $this->response->mapType($contentType);
+			return $response->mapType($contentType);
 		}
 		if (is_string($type)) {
-			return ($type === $this->response->mapType($contentType));
+			return ($type === $response->mapType($contentType));
 		}
 	}
 
@@ -451,12 +460,14 @@ class RequestHandlerComponent extends Component {
  *    If no type is provided the first preferred type is returned.
  */
 	public function prefers($type = null) {
-		$acceptRaw = $this->request->parseAccept();
+		$request = $this->request;
+		$response = $this->response;
+		$acceptRaw = $request->parseAccept();
 
 		if (empty($acceptRaw)) {
 			return $this->ext;
 		}
-		$accepts = $this->response->mapType(array_shift($acceptRaw));
+		$accepts = $response->mapType(array_shift($acceptRaw));
 
 		if (!$type) {
 			if (empty($this->ext) && !empty($accepts)) {
@@ -535,7 +546,8 @@ class RequestHandlerComponent extends Component {
 			$controller->layoutPath = $type;
 		}
 
-		if ($this->response->getMimeType($type)) {
+		$response = $this->response;
+		if ($response->getMimeType($type)) {
 			$this->respondAs($type, $options);
 		}
 
@@ -566,8 +578,10 @@ class RequestHandlerComponent extends Component {
 		$options += $defaults;
 
 		$cType = $type;
+		$request = $this->request;
+		$response = $this->response;
 		if (strpos($type, '/') === false) {
-			$cType = $this->response->getMimeType($type);
+			$cType = $response->getMimeType($type);
 		}
 		if (is_array($cType)) {
 			if (isset($cType[$options['index']])) {
@@ -585,13 +599,13 @@ class RequestHandlerComponent extends Component {
 			return false;
 		}
 		if (empty($this->request->params['requested'])) {
-			$this->response->type($cType);
+			$response->type($cType);
 		}
 		if (!empty($options['charset'])) {
-			$this->response->charset($options['charset']);
+			$response->charset($options['charset']);
 		}
 		if (!empty($options['attachment'])) {
-			$this->response->download($options['attachment']);
+			$response->download($options['attachment']);
 		}
 		return true;
 	}
@@ -603,7 +617,8 @@ class RequestHandlerComponent extends Component {
  *	otherwise null
  */
 	public function responseType() {
-		return $this->response->mapType($this->response->type());
+		$response = $this->response;
+		return $response->mapType($response->type());
 	}
 
 /**
@@ -617,7 +632,8 @@ class RequestHandlerComponent extends Component {
 		if (is_array($alias)) {
 			return array_map(array($this, 'mapAlias'), $alias);
 		}
-		$type = $this->response->getMimeType($alias);
+		$response = $this->response;
+		$type = $response->getMimeType($alias);
 		if ($type) {
 			if (is_array($type)) {
 				return $type[0];

+ 8 - 4
src/Controller/Controller.php

@@ -261,12 +261,16 @@ class Controller implements EventListener {
 			$this->viewPath = $viewPath;
 		}
 
-		if ($request instanceof Request) {
-			$this->setRequest($request);
+		if (!($request instanceof Request)) {
+			$request = new Request();
 		}
-		if ($response instanceof Response) {
-			$this->response = $response;
+		$this->setRequest($request);
+
+		if (!($response instanceof Response)) {
+			$response = new Response();
 		}
+		$this->response = $response;
+
 		if ($eventManager) {
 			$this->eventManager($eventManager);
 		}

+ 1 - 0
src/ORM/Table.php

@@ -230,6 +230,7 @@ class Table implements RepositoryInterface, EventListener {
 
 		$this->initialize($config);
 		$this->_eventManager->attach($this);
+		$this->dispatchEvent('Model.initialize');
 	}
 
 /**

+ 66 - 73
tests/TestCase/Controller/Component/RequestHandlerComponentTest.php

@@ -69,6 +69,7 @@ class RequestHandlerComponentTest extends TestCase {
 		$response = $this->getMock('Cake\Network\Response', array('_sendHeader', 'stop'));
 		$this->Controller = new RequestHandlerTestController($request, $response);
 		$this->RequestHandler = new RequestHandlerComponent($this->Controller->components());
+		$this->request = $request;
 
 		Router::scope('/', function ($routes) {
 			$routes->extensions('json');
@@ -109,10 +110,9 @@ class RequestHandlerComponentTest extends TestCase {
  * @return void
  */
 	public function testInitializeCallback() {
-		$event = new Event('Controller.initialize', $this->Controller);
 		$this->assertNull($this->RequestHandler->ext);
 		$this->Controller->request->params['_ext'] = 'rss';
-		$this->RequestHandler->initialize($event);
+		$this->RequestHandler->initialize([]);
 		$this->assertEquals('rss', $this->RequestHandler->ext);
 	}
 
@@ -122,13 +122,11 @@ class RequestHandlerComponentTest extends TestCase {
  * @return void
  */
 	public function testInitializeContentTypeSettingExt() {
-		$event = new Event('Controller.initialize', $this->Controller);
-		$_SERVER['HTTP_ACCEPT'] = 'application/json';
+		$this->request->env('HTTP_ACCEPT', 'application/json');
 		Router::extensions('json', false);
 
-		$this->assertNull($this->RequestHandler->ext);
-
-		$this->RequestHandler->initialize($event);
+		$this->RequestHandler->ext = null;
+		$this->RequestHandler->initialize([]);
 		$this->assertEquals('json', $this->RequestHandler->ext);
 	}
 
@@ -138,13 +136,12 @@ class RequestHandlerComponentTest extends TestCase {
  * @return void
  */
 	public function testInitializeContentTypeWithjQueryAccept() {
-		$_SERVER['HTTP_ACCEPT'] = 'application/json, application/javascript, */*; q=0.01';
-		$_SERVER['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest';
-		$event = new Event('Controller.initialize', $this->Controller);
-		$this->assertNull($this->RequestHandler->ext);
+		$this->request->env('HTTP_ACCEPT', 'application/json, application/javascript, */*; q=0.01');
+		$this->request->env('HTTP_X_REQUESTED_WITH', 'XMLHttpRequest');
+		$this->RequestHandler->ext = null;
 		Router::extensions('json', false);
 
-		$this->RequestHandler->initialize($event);
+		$this->RequestHandler->initialize([]);
 		$this->assertEquals('json', $this->RequestHandler->ext);
 	}
 
@@ -154,12 +151,10 @@ class RequestHandlerComponentTest extends TestCase {
  * @return void
  */
 	public function testInitializeContentTypeWithjQueryTextPlainAccept() {
-		$_SERVER['HTTP_ACCEPT'] = 'text/plain, */*; q=0.01';
-		$event = new Event('Controller.initialize', $this->Controller);
-		$this->assertNull($this->RequestHandler->ext);
 		Router::extensions('csv', false);
+		$this->request->env('HTTP_ACCEPT', 'text/plain, */*; q=0.01');
 
-		$this->RequestHandler->initialize($event);
+		$this->RequestHandler->initialize([]);
 		$this->assertNull($this->RequestHandler->ext);
 	}
 
@@ -170,12 +165,11 @@ class RequestHandlerComponentTest extends TestCase {
  * @return void
  */
 	public function testInitializeContentTypeWithjQueryAcceptAndMultiplesExtensions() {
-		$_SERVER['HTTP_ACCEPT'] = 'application/json, application/javascript, */*; q=0.01';
-		$event = new Event('Controller.initialize', $this->Controller);
-		$this->assertNull($this->RequestHandler->ext);
+		$this->request->env('HTTP_ACCEPT', 'application/json, application/javascript, */*; q=0.01');
+		$this->RequestHandler->ext = null;
 		Router::extensions(['rss', 'json'], false);
 
-		$this->RequestHandler->initialize($event);
+		$this->RequestHandler->initialize([]);
 		$this->assertEquals('json', $this->RequestHandler->ext);
 	}
 
@@ -186,11 +180,10 @@ class RequestHandlerComponentTest extends TestCase {
  */
 	public function testInitializeNoContentTypeWithSingleAccept() {
 		$_SERVER['HTTP_ACCEPT'] = 'application/json, text/html, */*; q=0.01';
-		$event = new Event('Controller.initialize', $this->Controller);
 		$this->assertNull($this->RequestHandler->ext);
 		Router::extensions('json', false);
 
-		$this->RequestHandler->initialize($event);
+		$this->RequestHandler->initialize([]);
 		$this->assertNull($this->RequestHandler->ext);
 	}
 
@@ -203,18 +196,20 @@ class RequestHandlerComponentTest extends TestCase {
  * @return void
  */
 	public function testInitializeNoContentTypeWithMultipleAcceptedTypes() {
-		$_SERVER['HTTP_ACCEPT'] = 'application/json, application/javascript, application/xml, */*; q=0.01';
-		$event = new Event('Controller.initialize', $this->Controller);
-		$this->assertNull($this->RequestHandler->ext);
+		$this->request->env(
+			'HTTP_ACCEPT',
+			'application/json, application/javascript, application/xml, */*; q=0.01'
+		);
+		$this->RequestHandler->ext = null;
 		Router::extensions(['xml', 'json'], false);
 
-		$this->RequestHandler->initialize($event);
+		$this->RequestHandler->initialize([]);
 		$this->assertEquals('xml', $this->RequestHandler->ext);
 
 		$this->RequestHandler->ext = null;
 		Router::extensions(array('json', 'xml'), false);
 
-		$this->RequestHandler->initialize($event);
+		$this->RequestHandler->initialize([]);
 		$this->assertEquals('json', $this->RequestHandler->ext);
 	}
 
@@ -224,12 +219,14 @@ class RequestHandlerComponentTest extends TestCase {
  * @return void
  */
 	public function testInitializeContentTypeWithMultipleAcceptedTypes() {
-		$_SERVER['HTTP_ACCEPT'] = 'text/csv;q=1.0, application/json;q=0.8, application/xml;q=0.7';
-		$event = new Event('Controller.initialize', $this->Controller);
-		$this->assertNull($this->RequestHandler->ext);
+		$this->request->env(
+			'HTTP_ACCEPT',
+			'text/csv;q=1.0, application/json;q=0.8, application/xml;q=0.7'
+		);
+		$this->RequestHandler->ext = null;
 		Router::extensions(['xml', 'json'], false);
 
-		$this->RequestHandler->initialize($event);
+		$this->RequestHandler->initialize([]);
 		$this->assertEquals('json', $this->RequestHandler->ext);
 	}
 
@@ -239,12 +236,14 @@ class RequestHandlerComponentTest extends TestCase {
  * @return void
  */
 	public function testInitializeAmbiguousAndroidAccepts() {
-		$_SERVER['HTTP_ACCEPT'] = 'application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5';
-		$event = new Event('Controller.initialize', $this->Controller);
-		$this->assertNull($this->RequestHandler->ext);
+		$this->request->env(
+			'HTTP_ACCEPT',
+			'application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5'
+		);
+		$this->RequestHandler->ext = null;
 		Router::extensions(['html', 'xml'], false);
 
-		$this->RequestHandler->initialize($event);
+		$this->RequestHandler->initialize([]);
 		$this->assertNull($this->RequestHandler->ext);
 	}
 
@@ -257,8 +256,7 @@ class RequestHandlerComponentTest extends TestCase {
 		$_SERVER['HTTP_ACCEPT'] = 'text/html,application/xhtml+xml,application/xml;image/png,image/jpeg,image/*;q=0.9,*/*;q=0.8';
 		Router::extensions(['xml', 'json'], false);
 
-		$event = new Event('Controller.initialize', $this->Controller);
-		$this->RequestHandler->initialize($event);
+		$this->RequestHandler->initialize([]);
 		$this->assertNull($this->RequestHandler->ext);
 	}
 
@@ -268,7 +266,6 @@ class RequestHandlerComponentTest extends TestCase {
  * @return void
  */
 	public function testInitializeContentTypeAndExtensionMismatch() {
-		$event = new Event('Controller.initialize', $this->Controller);
 		$this->assertNull($this->RequestHandler->ext);
 		$extensions = Router::extensions();
 		Router::extensions('xml', false);
@@ -278,7 +275,7 @@ class RequestHandlerComponentTest extends TestCase {
 			->method('accepts')
 			->will($this->returnValue(array('application/json')));
 
-		$this->RequestHandler->initialize($event);
+		$this->RequestHandler->initialize([]);
 		$this->assertNull($this->RequestHandler->ext);
 
 		call_user_func_array(array('Cake\Routing\Router', 'extensions'), [$extensions, false]);
@@ -290,9 +287,8 @@ class RequestHandlerComponentTest extends TestCase {
  * @return void
  */
 	public function testViewClassMap() {
-		$event = new Event('Controller.initialize', $this->Controller);
 		$this->RequestHandler->config(array('viewClassMap' => array('json' => 'CustomJson')));
-		$this->RequestHandler->initialize($event);
+		$this->RequestHandler->initialize([]);
 		$result = $this->RequestHandler->viewClassMap();
 		$expected = array(
 			'json' => 'CustomJson',
@@ -320,10 +316,9 @@ class RequestHandlerComponentTest extends TestCase {
  * @return void
  */
 	public function testDisabling() {
-		$_SERVER['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest';
-		$this->_init();
+		$this->request->env('HTTP_X_REQUESTED_WITH', 'XMLHttpRequest');
 		$event = new Event('Controller.startup', $this->Controller);
-		$this->RequestHandler->initialize($event);
+		$this->RequestHandler->initialize([]);
 		$this->Controller->beforeFilter($event);
 		$this->RequestHandler->startup($event);
 		$this->assertEquals(true, $this->Controller->request->params['isAjax']);
@@ -336,8 +331,8 @@ class RequestHandlerComponentTest extends TestCase {
  */
 	public function testAutoAjaxLayout() {
 		$event = new Event('Controller.startup', $this->Controller);
-		$_SERVER['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest';
-		$this->RequestHandler->initialize($event);
+		$this->request->env('HTTP_X_REQUESTED_WITH', 'XMLHttpRequest');
+		$this->RequestHandler->initialize([]);
 		$this->RequestHandler->startup($event);
 		$this->assertEquals($this->Controller->viewClass, 'Cake\View\AjaxView');
 		$view = $this->Controller->createView();
@@ -345,11 +340,9 @@ class RequestHandlerComponentTest extends TestCase {
 
 		$this->_init();
 		$this->Controller->request->params['_ext'] = 'js';
-		$this->RequestHandler->initialize($event);
+		$this->RequestHandler->initialize([]);
 		$this->RequestHandler->startup($event);
 		$this->assertNotEquals($this->Controller->viewClass, 'Cake\View\AjaxView');
-
-		unset($_SERVER['HTTP_X_REQUESTED_WITH']);
 	}
 
 /**
@@ -361,7 +354,7 @@ class RequestHandlerComponentTest extends TestCase {
 		Router::extensions(['json', 'xml', 'ajax'], false);
 		$this->Controller->request->params['_ext'] = 'json';
 		$event = new Event('Controller.startup', $this->Controller);
-		$this->RequestHandler->initialize($event);
+		$this->RequestHandler->initialize([]);
 		$this->RequestHandler->startup($event);
 		$this->assertEquals('Cake\View\JsonView', $this->Controller->viewClass);
 		$view = $this->Controller->createView();
@@ -378,7 +371,7 @@ class RequestHandlerComponentTest extends TestCase {
 		Router::extensions(['json', 'xml', 'ajax'], false);
 		$this->Controller->request->params['_ext'] = 'xml';
 		$event = new Event('Controller.startup', $this->Controller);
-		$this->RequestHandler->initialize($event);
+		$this->RequestHandler->initialize([]);
 		$this->RequestHandler->startup($event);
 		$this->assertEquals('Cake\View\XmlView', $this->Controller->viewClass);
 		$view = $this->Controller->createView();
@@ -395,7 +388,7 @@ class RequestHandlerComponentTest extends TestCase {
 		Router::extensions(['json', 'xml', 'ajax'], false);
 		$this->Controller->request->params['_ext'] = 'ajax';
 		$event = new Event('Controller.startup', $this->Controller);
-		$this->RequestHandler->initialize($event);
+		$this->RequestHandler->initialize([]);
 		$this->RequestHandler->startup($event);
 		$this->assertEquals('Cake\View\AjaxView', $this->Controller->viewClass);
 		$view = $this->Controller->createView();
@@ -411,7 +404,7 @@ class RequestHandlerComponentTest extends TestCase {
 		Router::extensions(['json', 'xml', 'ajax', 'csv'], false);
 		$this->Controller->request->params['_ext'] = 'csv';
 		$event = new Event('Controller.startup', $this->Controller);
-		$this->RequestHandler->initialize($event);
+		$this->RequestHandler->initialize([]);
 		$this->RequestHandler->startup($event);
 		$this->assertEquals('RequestHandlerTest' . DS . 'csv', $this->Controller->viewPath);
 		$this->assertEquals('csv', $this->Controller->layoutPath);
@@ -462,8 +455,8 @@ class RequestHandlerComponentTest extends TestCase {
 			->method('_readInput')
 			->will($this->returnValue('"A","csv","string"'));
 		$this->RequestHandler->addInputType('csv', array('str_getcsv'));
-		$this->RequestHandler->request->env('REQUEST_METHOD', 'POST');
-		$this->RequestHandler->request->env('CONTENT_TYPE', 'text/csv');
+		$this->request->env('REQUEST_METHOD', 'POST');
+		$this->request->env('CONTENT_TYPE', 'text/csv');
 		$this->RequestHandler->startup($event);
 		$expected = array(
 			'A', 'csv', 'string'
@@ -478,7 +471,7 @@ class RequestHandlerComponentTest extends TestCase {
  */
 	public function testNonAjaxRedirect() {
 		$event = new Event('Controller.startup', $this->Controller);
-		$this->RequestHandler->initialize($event);
+		$this->RequestHandler->initialize([]);
 		$this->RequestHandler->startup($event);
 		$this->assertNull($this->RequestHandler->beforeRedirect($event, '/', $this->Controller->response));
 	}
@@ -496,7 +489,7 @@ class RequestHandlerComponentTest extends TestCase {
 		$this->Controller->response->expects($this->never())
 			->method('body');
 
-		$this->RequestHandler->initialize($event);
+		$this->RequestHandler->initialize([]);
 		$this->RequestHandler->startup($event);
 		$this->assertNull($this->RequestHandler->beforeRedirect($event, null, $this->Controller->response));
 	}
@@ -610,11 +603,11 @@ class RequestHandlerComponentTest extends TestCase {
  * @return void
  */
 	public function testRequestContentTypes() {
-		$this->RequestHandler->request->env('REQUEST_METHOD', 'GET');
+		$this->request->env('REQUEST_METHOD', 'GET');
 		$this->assertNull($this->RequestHandler->requestedWith());
 
-		$this->RequestHandler->request->env('REQUEST_METHOD', 'POST');
-		$this->RequestHandler->request->env('CONTENT_TYPE', 'application/json');
+		$this->request->env('REQUEST_METHOD', 'POST');
+		$this->request->env('CONTENT_TYPE', 'application/json');
 		$this->assertEquals('json', $this->RequestHandler->requestedWith());
 
 		$result = $this->RequestHandler->requestedWith(array('json', 'xml'));
@@ -623,12 +616,12 @@ class RequestHandlerComponentTest extends TestCase {
 		$result = $this->RequestHandler->requestedWith(array('rss', 'atom'));
 		$this->assertFalse($result);
 
-		$this->RequestHandler->request->env('REQUEST_METHOD', 'DELETE');
+		$this->request->env('REQUEST_METHOD', 'DELETE');
 		$this->assertEquals('json', $this->RequestHandler->requestedWith());
 
-		$this->RequestHandler->request->env('REQUEST_METHOD', 'POST');
-		$this->RequestHandler->request->env('CONTENT_TYPE', '');
-		$this->RequestHandler->request->env('HTTP_CONTENT_TYPE', 'application/json');
+		$this->request->env('REQUEST_METHOD', 'POST');
+		$this->request->env('CONTENT_TYPE', '');
+		$this->request->env('HTTP_CONTENT_TYPE', 'application/json');
 
 		$result = $this->RequestHandler->requestedWith(array('json', 'xml'));
 		$this->assertEquals('json', $result);
@@ -636,21 +629,21 @@ class RequestHandlerComponentTest extends TestCase {
 		$result = $this->RequestHandler->requestedWith(array('rss', 'atom'));
 		$this->assertFalse($result);
 
-		$this->RequestHandler->request->env('HTTP_ACCEPT', 'text/xml,application/xml,application/xhtml+xml,text/html,text/plain,image/png,*/*');
+		$this->request->env('HTTP_ACCEPT', 'text/xml,application/xml,application/xhtml+xml,text/html,text/plain,image/png,*/*');
 		$this->assertTrue($this->RequestHandler->isXml());
 		$this->assertFalse($this->RequestHandler->isAtom());
 		$this->assertFalse($this->RequestHandler->isRSS());
 
-		$this->RequestHandler->request->env('HTTP_ACCEPT', 'application/atom+xml,text/xml,application/xml,application/xhtml+xml,text/html,text/plain,image/png,*/*');
+		$this->request->env('HTTP_ACCEPT', 'application/atom+xml,text/xml,application/xml,application/xhtml+xml,text/html,text/plain,image/png,*/*');
 		$this->assertTrue($this->RequestHandler->isAtom());
 		$this->assertFalse($this->RequestHandler->isRSS());
 
-		$this->RequestHandler->request->env('HTTP_ACCEPT', 'application/rss+xml,text/xml,application/xml,application/xhtml+xml,text/html,text/plain,image/png,*/*');
+		$this->request->env('HTTP_ACCEPT', 'application/rss+xml,text/xml,application/xml,application/xhtml+xml,text/html,text/plain,image/png,*/*');
 		$this->assertFalse($this->RequestHandler->isAtom());
 		$this->assertTrue($this->RequestHandler->isRSS());
 
 		$this->assertFalse($this->RequestHandler->isWap());
-		$this->RequestHandler->request->env('HTTP_ACCEPT', 'text/vnd.wap.wml,text/html,text/plain,image/png,*/*');
+		$this->request->env('HTTP_ACCEPT', 'text/vnd.wap.wml,text/html,text/plain,image/png,*/*');
 		$this->assertTrue($this->RequestHandler->isWap());
 	}
 
@@ -706,11 +699,11 @@ class RequestHandlerComponentTest extends TestCase {
  * @return void
  */
 	public function testAccepts() {
-		$_SERVER['HTTP_ACCEPT'] = 'text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5';
+		$this->request->env('HTTP_ACCEPT', 'text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5');
 		$this->assertTrue($this->RequestHandler->accepts(array('js', 'xml', 'html')));
 		$this->assertFalse($this->RequestHandler->accepts(array('gif', 'jpeg', 'foo')));
 
-		$_SERVER['HTTP_ACCEPT'] = '*/*;q=0.5';
+		$this->request->env('HTTP_ACCEPT', '*/*;q=0.5');
 		$this->assertFalse($this->RequestHandler->accepts('rss'));
 	}
 
@@ -720,7 +713,7 @@ class RequestHandlerComponentTest extends TestCase {
  * @return void
  */
 	public function testPrefers() {
-		$this->RequestHandler->request->env(
+		$this->request->env(
 			'HTTP_ACCEPT',
 			'text/xml,application/xml,application/xhtml+xml,text/html,text/plain,image/png,*/*'
 		);
@@ -735,13 +728,13 @@ class RequestHandlerComponentTest extends TestCase {
 		$this->assertFalse($this->RequestHandler->prefers(array('html')), 'No match with ext, return false.');
 
 		$this->_init();
-		$this->RequestHandler->request->env(
+		$this->request->env(
 			'HTTP_ACCEPT',
 			'text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5'
 		);
 		$this->assertEquals('xml', $this->RequestHandler->prefers());
 
-		$this->RequestHandler->request->env('HTTP_ACCEPT', '*/*;q=0.5');
+		$this->request->env('HTTP_ACCEPT', '*/*;q=0.5');
 		$this->assertEquals('html', $this->RequestHandler->prefers());
 		$this->assertFalse($this->RequestHandler->prefers('rss'));
 	}

+ 2 - 2
tests/TestCase/Controller/ControllerTest.php

@@ -148,10 +148,10 @@ class TestComponent extends Component {
 /**
  * initialize method
  *
- * @param Event $event
+ * @param array $config
  * @return void
  */
-	public function initialize(Event $event) {
+	public function initialize(array $config) {
 	}
 
 /**

+ 2 - 2
tests/TestCase/Error/ExceptionRendererTest.php

@@ -56,10 +56,10 @@ class BlueberryComponent extends Component {
 /**
  * initialize method
  *
- * @param Event $event
+ * @param array $config
  * @return void
  */
-	public function initialize(Event $event) {
+	public function initialize(array $config) {
 		$this->testName = 'BlueberryComponent';
 	}
 

+ 29 - 3
tests/TestCase/ORM/TableTest.php

@@ -19,6 +19,7 @@ use Cake\Database\Expression\OrderByExpression;
 use Cake\Database\Expression\QueryExpression;
 use Cake\Database\TypeMap;
 use Cake\Datasource\ConnectionManager;
+use Cake\Event\EventManager;
 use Cake\I18n\Time;
 use Cake\ORM\Table;
 use Cake\ORM\TableRegistry;
@@ -81,6 +82,11 @@ class TableTest extends \Cake\TestSuite\TestCase {
 		]);
 	}
 
+/**
+ * teardown method
+ *
+ * @return void
+ */
 	public function tearDown() {
 		parent::tearDown();
 		TableRegistry::clear();
@@ -1902,6 +1908,9 @@ class TableTest extends \Cake\TestSuite\TestCase {
 			->method('attach');
 
 		$mock->expects($this->at(1))
+			->method('dispatch');
+
+		$mock->expects($this->at(2))
 			->method('dispatch')
 			->with($this->logicalAnd(
 				$this->attributeEqualTo('_name', 'Model.beforeDelete'),
@@ -1911,7 +1920,7 @@ class TableTest extends \Cake\TestSuite\TestCase {
 				)
 			));
 
-		$mock->expects($this->at(2))
+		$mock->expects($this->at(3))
 			->method('dispatch')
 			->with($this->logicalAnd(
 				$this->attributeEqualTo('_name', 'Model.afterDelete'),
@@ -1936,7 +1945,7 @@ class TableTest extends \Cake\TestSuite\TestCase {
 		$options = new \ArrayObject(['atomic' => true, 'cascade' => true]);
 
 		$mock = $this->getMock('Cake\Event\EventManager');
-		$mock->expects($this->once())
+		$mock->expects($this->at(2))
 			->method('dispatch')
 			->will($this->returnCallback(function ($event) {
 				$event->stopPropagation();
@@ -1958,7 +1967,7 @@ class TableTest extends \Cake\TestSuite\TestCase {
 		$options = new \ArrayObject(['atomic' => true, 'cascade' => true]);
 
 		$mock = $this->getMock('Cake\Event\EventManager');
-		$mock->expects($this->once())
+		$mock->expects($this->at(2))
 			->method('dispatch')
 			->will($this->returnCallback(function ($event) {
 				$event->stopPropagation();
@@ -3658,4 +3667,21 @@ class TableTest extends \Cake\TestSuite\TestCase {
 		$this->assertEquals(2, $article->author_id);
 	}
 
+/**
+ * Test that creating a table fires the initialize event.
+ *
+ * @return void
+ */
+	public function testInitializeEvent() {
+		$count = 0;
+		$cb = function ($event) use (&$count){
+			$count++;
+		};
+		EventManager::instance()->attach($cb, 'Model.initialize');
+		$articles = TableRegistry::get('Articles');
+
+		$this->assertEquals(1, $count, 'Callback should be called');
+		EventManager::instance()->detach($cb, 'Model.initialize');
+	}
+
 }

+ 3 - 4
tests/test_app/TestApp/Controller/Component/OrangeComponent.php

@@ -33,12 +33,11 @@ class OrangeComponent extends Component {
 /**
  * initialize method
  *
- * @param Event $event
- * @param Controller $controller
+ * @param array $config
  * @return void
  */
-	public function initialize(Event $event) {
-		$this->Controller = $event->subject();
+	public function initialize(array $config) {
+		$this->Controller = $this->_registry->getController();
 		$this->Banana->testField = 'OrangeField';
 	}