Browse Source

Adding a new exception renderer method to show useful error for failed queries

Jose Lorenzo Rodriguez 14 years ago
parent
commit
3d0af8b690

+ 2 - 0
lib/Cake/Controller/PagesController.php

@@ -59,6 +59,8 @@ class PagesController extends AppController {
  * @return void
  */
 	public function display() {
+		App::uses('ConnectionManager', 'Model');
+		ConnectionManager::getDatasource('default')->execute('dasd kdjskljklda dljsdljadlas dkjadjasldkas dlajdklajdla dajsdlajdlka');
 		$path = func_get_args();
 
 		$count = count($path);

+ 28 - 1
lib/Cake/Error/ExceptionRenderer.php

@@ -107,6 +107,10 @@ class ExceptionRenderer {
 			if ($template == 'internalError') {
 				$template = 'error500';
 			}
+		} elseif ($exception instanceof PDOException) {
+			$method = 'pdoError';
+			$template = 'pdo_error';
+			$code = 500;
 		} elseif (!$methodExists) {
 			$method = 'error500';
 			if ($code >= 400 && $code < 500) {
@@ -220,7 +224,7 @@ class ExceptionRenderer {
  */
 	public function error500($error) {
 		$url = $this->controller->request->here();
-		$code = ($error->getCode() > 500) ? $error->getCode() : 500;
+		$code = ($error->getCode() > 500 && $error->getCode() < 506) ? $error->getCode() : 500;
 		$this->controller->response->statusCode($code);
 		$this->controller->set(array(
 			'name' => __d('cake', 'An Internal Error Has Occurred'),
@@ -231,6 +235,29 @@ class ExceptionRenderer {
 	}
 
 /**
+ * Convenience method to display a PDOException.
+ *
+ * @param PDOException $error 
+ * @return void
+ */
+	public function pdoError(PDOException $error) {
+		$url = $this->controller->request->here();
+		$code = 500;
+		$this->controller->response->statusCode($code);
+		$this->controller->set(array(
+			'code' => $code,
+			'url' => h($url),
+			'name' => $error->getMessage(),
+			'error' => $error,
+		));
+		try {
+			$this->_outputMessage($this->template);
+		} catch (Exception $e) {
+			$this->_outputMessageSafe('error500');
+		}
+	}
+
+/**
  * Generate the response using the controller object.
  *
  * @param string $template The template to render.

+ 20 - 11
lib/Cake/Model/Datasource/DboSource.php

@@ -430,18 +430,27 @@ class DboSource extends DataSource {
 			}
 		}
 
-		$query = $this->_connection->prepare($sql, $prepareOptions);
-		$query->setFetchMode(PDO::FETCH_LAZY);
-		if (!$query->execute($params)) {
-			$this->_results = $query;
-			$query->closeCursor();
-			return false;
-		}
-		if (!$query->columnCount()) {
-			$query->closeCursor();
-			return true;
+		try {
+			$query = $this->_connection->prepare($sql, $prepareOptions);
+			$query->setFetchMode(PDO::FETCH_LAZY);
+			if (!$query->execute($params)) {
+				$this->_results = $query;
+				$query->closeCursor();
+				return false;
+			}
+			if (!$query->columnCount()) {
+				$query->closeCursor();
+				return true;
+			}
+			return $query;
+		} catch (PDOException $e) {
+			if (isset($query->queryString)) {
+				$e->queryString = $query->queryString;
+			} else {
+				$e->queryString = $sql;
+			}
+			throw $e;
 		}
-		return $query;
 	}
 
 /**

+ 23 - 0
lib/Cake/Test/Case/Error/ExceptionRendererTest.php

@@ -665,4 +665,27 @@ class ExceptionRendererTest extends CakeTestCase {
 
 		$this->assertContains('Internal Error', $result);
 	}
+
+/**
+ * Tests the output of rendering a PDOException
+ *
+ * @return void
+ */
+	public function testPDOException() {
+		$exception = new PDOException('There was an error in the SQL query');
+		$exception->queryString = 'SELECT * from poo_query < 5 and :seven';
+		$exception->params = array('seven' => 7);
+		$ExceptionRenderer = new ExceptionRenderer($exception);
+		$ExceptionRenderer->controller->response = $this->getMock('CakeResponse', array('statusCode', '_sendHeader'));
+		$ExceptionRenderer->controller->response->expects($this->once())->method('statusCode')->with(500);
+
+		ob_start();
+		$ExceptionRenderer->render();
+		$result = ob_get_clean();
+
+		$this->assertPattern('/<h2>Database Error<\/h2>/', $result);
+		$this->assertPattern('/There was an error in the SQL query/', $result);
+		$this->assertPattern('/SELECT \* from poo_query < 5 and :seven/', $result);
+		$this->assertPattern('/"seven" => 7/', $result);
+	}
 }

+ 38 - 0
lib/Cake/View/Errors/pdo_error.ctp

@@ -0,0 +1,38 @@
+<?php
+/**
+ *
+ * PHP 5
+ *
+ * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
+ * Copyright 2005-2011, Cake Software Foundation, Inc. (http://cakefoundation.org)
+ *
+ * Licensed under The MIT License
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @copyright     Copyright 2005-2011, Cake Software Foundation, Inc. (http://cakefoundation.org)
+ * @link          http://cakephp.org CakePHP(tm) Project
+ * @package       cake.libs.view.templates.errors
+ * @since         CakePHP(tm) v 0.10.0.1076
+ * @license       MIT License (http://www.opensource.org/licenses/mit-license.php)
+ */
+?>
+<h2><?php echo __d('cake_dev', 'Database Error'); ?></h2>
+<p class="error">
+	<strong><?php echo __d('cake_dev', 'Error'); ?>: </strong>
+	<?php echo h($error->getMessage()); ?>
+</p>
+<?php if (!empty($error->queryString)) : ?>
+	<p class="notice">
+		<strong><?php echo __d('cake_dev', 'SQL Query'); ?>: </strong>
+		<?php echo  $error->queryString; ?>
+	</p>
+<?php endif; ?>
+<?php if (!empty($error->params)) : ?>
+		<strong><?php echo __d('cake_dev', 'SQL Query Params'); ?>: </strong>
+		<?php echo  Debugger::dump($error->params); ?>
+<?php endif; ?>
+<p class="notice">
+	<strong><?php echo __d('cake_dev', 'Notice'); ?>: </strong>
+	<?php echo __d('cake_dev', 'If you want to customize this error message, create %s', APP_DIR . DS . 'View' . DS . 'Errors' . DS . 'pdo_error.ctp'); ?>
+</p>
+<?php echo $this->element('exception_stack_trace'); ?>