Skip to content
This repository
Browse code

Merge remote-tracking branch 'origin/2.2' into 2.2

  • Loading branch information...
commit e7a7a177cc98311bc2974babaf326d92dac1254b 2 parents 63c0c2c + 7e38f9d
José Lorenzo Rodríguez authored April 23, 2012

Showing 50 changed files with 719 additions and 577 deletions. Show diff stats Hide diff stats

  1. 29  app/Config/bootstrap.php
  2. 2  app/View/Layouts/ajax.ctp
  3. 2  app/View/Layouts/js/default.ctp
  4. 4  app/View/Layouts/rss/default.ctp
  5. 2  app/View/Layouts/xml/default.ctp
  6. 10  lib/Cake/Cache/CacheEngine.php
  7. 6  lib/Cake/Cache/Engine/RedisEngine.php
  8. 4  lib/Cake/Console/Command/Task/ExtractTask.php
  9. 31  lib/Cake/Console/Templates/skel/Config/bootstrap.php
  10. 4  lib/Cake/Console/Templates/skel/View/Layouts/Emails/html/default.ctp
  11. 2  lib/Cake/Console/Templates/skel/View/Layouts/Emails/text/default.ctp
  12. 2  lib/Cake/Console/Templates/skel/View/Layouts/ajax.ctp
  13. 2  lib/Cake/Console/Templates/skel/View/Layouts/js/default.ctp
  14. 4  lib/Cake/Console/Templates/skel/View/Layouts/rss/default.ctp
  15. 2  lib/Cake/Console/Templates/skel/View/Layouts/xml/default.ctp
  16. 27  lib/Cake/Controller/Component/EmailComponent.php
  17. 29  lib/Cake/Model/Datasource/Database/Mysql.php
  18. 20  lib/Cake/Model/Datasource/Database/Postgres.php
  19. 9  lib/Cake/Model/Datasource/Database/Sqlite.php
  20. 22  lib/Cake/Model/Datasource/Database/Sqlserver.php
  21. 142  lib/Cake/Model/Datasource/DboSource.php
  22. 2  lib/Cake/Model/Model.php
  23. 40  lib/Cake/Network/CakeRequest.php
  24. 9  lib/Cake/Routing/Dispatcher.php
  25. 16  lib/Cake/Routing/Filter/CacheDispatcher.php
  26. 3  lib/Cake/Routing/Router.php
  27. 2  lib/Cake/Test/Case/Cache/Engine/FileEngineTest.php
  28. 3  lib/Cake/Test/Case/Cache/Engine/RedisEngineTest.php
  29. 3  lib/Cake/Test/Case/Controller/Component/Auth/FormAuthenticateTest.php
  30. 18  lib/Cake/Test/Case/Controller/Component/EmailComponentTest.php
  31. 36  lib/Cake/Test/Case/Model/Datasource/Database/MysqlTest.php
  32. 33  lib/Cake/Test/Case/Model/Datasource/Database/PostgresTest.php
  33. 33  lib/Cake/Test/Case/Model/Datasource/Database/SqliteTest.php
  34. 79  lib/Cake/Test/Case/Model/Datasource/DboSourceTest.php
  35. 3  lib/Cake/Test/Case/Model/ModelIntegrationTest.php
  36. 161  lib/Cake/Test/Case/Model/ModelWriteTest.php
  37. 192  lib/Cake/Test/Case/Network/CakeRequestTest.php
  38. 15  lib/Cake/Test/Case/Routing/DispatcherTest.php
  39. 16  lib/Cake/Test/Case/Routing/Filter/AssetDispatcherTest.php
  40. 23  lib/Cake/Test/Case/TestSuite/CakeTestSuiteTest.php
  41. 1  lib/Cake/Test/Case/Utility/InflectorTest.php
  42. 122  lib/Cake/Test/Case/View/Helper/FormHelperTest.php
  43. 54  lib/Cake/Test/Case/View/Helper/HtmlHelperTest.php
  44. 10  lib/Cake/TestSuite/CakeTestCase.php
  45. 8  lib/Cake/TestSuite/CakeTestSuite.php
  46. 26  lib/Cake/TestSuite/CakeTestSuiteDispatcher.php
  47. 15  lib/Cake/TestSuite/Fixture/CakeTestModel.php
  48. 12  lib/Cake/TestSuite/Reporter/CakeHtmlReporter.php
  49. 2  lib/Cake/Utility/Inflector.php
  50. 4  lib/Cake/View/HelperCollection.php
29  app/Config/bootstrap.php
@@ -89,17 +89,24 @@
89 89
  * The settings below can be used to set additional paths to models, views and controllers.
90 90
  *
91 91
  * App::build(array(
92  
- *     'Plugin' => array('/full/path/to/plugins/', '/next/full/path/to/plugins/'),
93  
- *     'Model' =>  array('/full/path/to/models/', '/next/full/path/to/models/'),
94  
- *     'View' => array('/full/path/to/views/', '/next/full/path/to/views/'),
95  
- *     'Controller' => array('/full/path/to/controllers/', '/next/full/path/to/controllers/'),
96  
- *     'Model/Datasource' => array('/full/path/to/datasources/', '/next/full/path/to/datasources/'),
97  
- *     'Model/Behavior' => array('/full/path/to/behaviors/', '/next/full/path/to/behaviors/'),
98  
- *     'Controller/Component' => array('/full/path/to/components/', '/next/full/path/to/components/'),
99  
- *     'View/Helper' => array('/full/path/to/helpers/', '/next/full/path/to/helpers/'),
100  
- *     'Vendor' => array('/full/path/to/vendors/', '/next/full/path/to/vendors/'),
101  
- *     'Console/Command' => array('/full/path/to/shells/', '/next/full/path/to/shells/'),
102  
- *     'Locale' => array('/full/path/to/locale/', '/next/full/path/to/locale/')
  92
+ *     'Model'                     => array('/path/to/models', '/next/path/to/models'),
  93
+ *     'Model/Behavior'            => array('/path/to/behaviors', '/next/path/to/behaviors'),
  94
+ *     'Model/Datasource'          => array('/path/to/datasources', '/next/path/to/datasources'),
  95
+ *     'Model/Datasource/Database' => array('/path/to/databases', '/next/path/to/database'),
  96
+ *     'Model/Datasource/Session'  => array('/path/to/sessions', '/next/path/to/sessions'),
  97
+ *     'Controller'                => array('/path/to/controllers', '/next/path/to/controllers'),
  98
+ *     'Controller/Component'      => array('/path/to/components', '/next/path/to/components'),
  99
+ *     'Controller/Component/Auth' => array('/path/to/auths', '/next/path/to/auths'),
  100
+ *     'Controller/Component/Acl'  => array('/path/to/acls', '/next/path/to/acls'),
  101
+ *     'View'                      => array('/path/to/views', '/next/path/to/views'),
  102
+ *     'View/Helper'               => array('/path/to/helpers', '/next/path/to/helpers'),
  103
+ *     'Console'                   => array('/path/to/consoles', '/next/path/to/consoles'),
  104
+ *     'Console/Command'           => array('/path/to/commands', '/next/path/to/commands'),
  105
+ *     'Console/Command/Task'      => array('/path/to/tasks', '/next/path/to/tasks'),
  106
+ *     'Lib'                       => array('/path/to/libs', '/next/path/to/libs'),
  107
+ *     'Locale'                    => array('/path/to/locales', '/next/path/to/locales'),
  108
+ *     'Vendor'                    => array('/path/to/vendors', '/next/path/to/vendors'),
  109
+ *     'Plugin'                    => array('/path/to/plugins', '/next/path/to/plugins'),
103 110
  * ));
104 111
  *
105 112
  */
2  app/View/Layouts/ajax.ctp
@@ -16,4 +16,4 @@
16 16
  * @license       MIT License (http://www.opensource.org/licenses/mit-license.php)
17 17
  */
18 18
 ?>
19  
-<?php echo $content_for_layout; ?>
  19
+<?php echo $this->fetch('content'); ?>
2  app/View/Layouts/js/default.ctp
... ...
@@ -1,2 +1,2 @@
1 1
 <?php echo $scripts_for_layout; ?>
2  
-<script type="text/javascript"><?php echo $content_for_layout; ?></script>
  2
+<script type="text/javascript"><?php echo $this->fetch('content'); ?></script>
4  app/View/Layouts/rss/default.ctp
@@ -8,7 +8,7 @@ if (!isset($channel['title'])) {
8 8
 
9 9
 echo $this->Rss->document(
10 10
 	$this->Rss->channel(
11  
-		array(), $channel, $content_for_layout
  11
+		array(), $channel, $this->fetch('content')
12 12
 	)
13 13
 );
14  
-?>
  14
+?>
2  app/View/Layouts/xml/default.ctp
... ...
@@ -1 +1 @@
1  
-<?php echo $content_for_layout; ?>
  1
+<?php echo $this->fetch('content'); ?>
10  lib/Cake/Cache/CacheEngine.php
@@ -129,7 +129,7 @@ public function gc($expires = null) {
129 129
  *
130 130
  * @param string $groups name of the group to be cleared
131 131
  * @return boolean
132  
- **/
  132
+ */
133 133
 	public function clearGroup($group) {
134 134
 		return false;
135 135
 	}
@@ -140,10 +140,10 @@ public function clearGroup($group) {
140 140
  * the token representing each group in the cache key
141 141
  *
142 142
  * @return array
143  
- **/
144  
- 	public function groups() {
145  
- 		return $this->settings['groups'];
146  
- 	}
  143
+ */
  144
+	public function groups() {
  145
+		return $this->settings['groups'];
  146
+	}
147 147
 
148 148
 /**
149 149
  * Cache Engine settings
6  lib/Cake/Cache/Engine/RedisEngine.php
@@ -115,7 +115,7 @@ public function write($key, $value, $duration) {
115 115
 	public function read($key) {
116 116
 		$value = $this->_Redis->get($key);
117 117
 		if (ctype_digit($value)) {
118  
-			$value = (int) $value;
  118
+			$value = (int)$value;
119 119
 		}
120 120
 		if ($value !== false && is_string($value)) {
121 121
 			$value = unserialize($value);
@@ -132,7 +132,7 @@ public function read($key) {
132 132
  * @throws CacheException when you try to increment with compress = true
133 133
  */
134 134
 	public function increment($key, $offset = 1) {
135  
-		return (int) $this->_Redis->incrBy($key, $offset);
  135
+		return (int)$this->_Redis->incrBy($key, $offset);
136 136
 	}
137 137
 
138 138
 /**
@@ -144,7 +144,7 @@ public function increment($key, $offset = 1) {
144 144
  * @throws CacheException when you try to decrement with compress = true
145 145
  */
146 146
 	public function decrement($key, $offset = 1) {
147  
-		return (int) $this->_Redis->decrBy($key, $offset);
  147
+		return (int)$this->_Redis->decrBy($key, $offset);
148 148
 	}
149 149
 
150 150
 /**
4  lib/Cake/Console/Command/Task/ExtractTask.php
@@ -464,6 +464,8 @@ protected function _processValidationRules($field, $rules, $file, $domain) {
464 464
  * @return void
465 465
  */
466 466
 	protected function _buildFiles() {
  467
+		$paths = $this->_paths;
  468
+		$paths[] = realpath(APP) . DS;
467 469
 		foreach ($this->_translations as $domain => $translations) {
468 470
 			foreach ($translations as $msgid => $details) {
469 471
 				$plural = $details['msgid_plural'];
@@ -474,7 +476,7 @@ protected function _buildFiles() {
474 476
 					$occurrences[] = $file . ':' . implode(';', $lines);
475 477
 				}
476 478
 				$occurrences = implode("\n#: ", $occurrences);
477  
-				$header = '#: ' . str_replace($this->_paths, '', $occurrences) . "\n";
  479
+				$header = '#: ' . str_replace($paths, '', $occurrences) . "\n";
478 480
 
479 481
 				if ($plural === false) {
480 482
 					$sentence = "msgid \"{$msgid}\"\n";
31  lib/Cake/Console/Templates/skel/Config/bootstrap.php
@@ -30,17 +30,24 @@
30 30
  * The settings below can be used to set additional paths to models, views and controllers.
31 31
  *
32 32
  * App::build(array(
33  
- *     'Plugin' => array('/full/path/to/plugins/', '/next/full/path/to/plugins/'),
34  
- *     'Model' =>  array('/full/path/to/models/', '/next/full/path/to/models/'),
35  
- *     'View' => array('/full/path/to/views/', '/next/full/path/to/views/'),
36  
- *     'Controller' => array('/full/path/to/controllers/', '/next/full/path/to/controllers/'),
37  
- *     'Model/Datasource' => array('/full/path/to/datasources/', '/next/full/path/to/datasources/'),
38  
- *     'Model/Behavior' => array('/full/path/to/behaviors/', '/next/full/path/to/behaviors/'),
39  
- *     'Controller/Component' => array('/full/path/to/components/', '/next/full/path/to/components/'),
40  
- *     'View/Helper' => array('/full/path/to/helpers/', '/next/full/path/to/helpers/'),
41  
- *     'Vendor' => array('/full/path/to/vendors/', '/next/full/path/to/vendors/'),
42  
- *     'Console/Command' => array('/full/path/to/shells/', '/next/full/path/to/shells/'),
43  
- *     'Locale' => array('/full/path/to/locale/', '/next/full/path/to/locale/')
  33
+ *     'Model'                     => array('/path/to/models', '/next/path/to/models'),
  34
+ *     'Model/Behavior'            => array('/path/to/behaviors', '/next/path/to/behaviors'),
  35
+ *     'Model/Datasource'          => array('/path/to/datasources', '/next/path/to/datasources'),
  36
+ *     'Model/Datasource/Database' => array('/path/to/databases', '/next/path/to/database'),
  37
+ *     'Model/Datasource/Session'  => array('/path/to/sessions', '/next/path/to/sessions'),
  38
+ *     'Controller'                => array('/path/to/controllers', '/next/path/to/controllers'),
  39
+ *     'Controller/Component'      => array('/path/to/components', '/next/path/to/components'),
  40
+ *     'Controller/Component/Auth' => array('/path/to/auths', '/next/path/to/auths'),
  41
+ *     'Controller/Component/Acl'  => array('/path/to/acls', '/next/path/to/acls'),
  42
+ *     'View'                      => array('/path/to/views', '/next/path/to/views'),
  43
+ *     'View/Helper'               => array('/path/to/helpers', '/next/path/to/helpers'),
  44
+ *     'Console'                   => array('/path/to/consoles', '/next/path/to/consoles'),
  45
+ *     'Console/Command'           => array('/path/to/commands', '/next/path/to/commands'),
  46
+ *     'Console/Command/Task'      => array('/path/to/tasks', '/next/path/to/tasks'),
  47
+ *     'Lib'                       => array('/path/to/libs', '/next/path/to/libs'),
  48
+ *     'Locale'                    => array('/path/to/locales', '/next/path/to/locales'),
  49
+ *     'Vendor'                    => array('/path/to/vendors', '/next/path/to/vendors'),
  50
+ *     'Plugin'                    => array('/path/to/plugins', '/next/path/to/plugins'),
44 51
  * ));
45 52
  *
46 53
  */
@@ -83,4 +90,4 @@
83 90
 Configure::write('Dispatcher.filters', array(
84 91
 	'AssetDispatcher',
85 92
 	'CacheDispatcher'
86  
-));
  93
+));
4  lib/Cake/Console/Templates/skel/View/Layouts/Emails/html/default.ctp
@@ -24,8 +24,8 @@
24 24
 </head>
25 25
 
26 26
 <body>
27  
-	<?php echo $content_for_layout;?>
  27
+	<?php echo $this->fetch('content');?>
28 28
 
29 29
 	<p>This email was sent using the <a href="http://cakephp.org">CakePHP Framework</a></p>
30 30
 </body>
31  
-</html>
  31
+</html>
2  lib/Cake/Console/Templates/skel/View/Layouts/Emails/text/default.ctp
@@ -17,6 +17,6 @@
17 17
  */
18 18
 ?>
19 19
 
20  
-<?php echo $content_for_layout;?>
  20
+<?php echo $this->fetch('content');?>
21 21
 
22 22
 This email was sent using the CakePHP Framework, http://cakephp.org.
2  lib/Cake/Console/Templates/skel/View/Layouts/ajax.ctp
@@ -16,4 +16,4 @@
16 16
  * @license       MIT License (http://www.opensource.org/licenses/mit-license.php)
17 17
  */
18 18
 ?>
19  
-<?php echo $content_for_layout; ?>
  19
+<?php echo $this->fetch('content'); ?>
2  lib/Cake/Console/Templates/skel/View/Layouts/js/default.ctp
... ...
@@ -1,2 +1,2 @@
1 1
 <?php echo $scripts_for_layout; ?>
2  
-<script type="text/javascript"><?php echo $content_for_layout; ?></script>
  2
+<script type="text/javascript"><?php echo $this->fetch('content'); ?></script>
4  lib/Cake/Console/Templates/skel/View/Layouts/rss/default.ctp
@@ -8,7 +8,7 @@ if (!isset($channel['title'])) {
8 8
 
9 9
 echo $this->Rss->document(
10 10
 	$this->Rss->channel(
11  
-		array(), $channel, $content_for_layout
  11
+		array(), $channel, $this->fetch('content')
12 12
 	)
13 13
 );
14  
-?>
  14
+?>
2  lib/Cake/Console/Templates/skel/View/Layouts/xml/default.ctp
... ...
@@ -1 +1 @@
1  
-<?php echo $content_for_layout; ?>
  1
+<?php echo $this->fetch('content'); ?>
27  lib/Cake/Controller/Component/EmailComponent.php
@@ -421,31 +421,6 @@ protected function _findFiles($attachment) {
421 421
 	}
422 422
 
423 423
 /**
424  
- * Encode the specified string using the current charset
425  
- *
426  
- * @param string $subject String to encode
427  
- * @return string Encoded string
428  
- */
429  
-	protected function _encode($subject) {
430  
-		$subject = $this->_strip($subject);
431  
-
432  
-		$nl = "\r\n";
433  
-		if ($this->delivery == 'mail') {
434  
-			$nl = '';
435  
-		}
436  
-		$internalEncoding = function_exists('mb_internal_encoding');
437  
-		if ($internalEncoding) {
438  
-			$restore = mb_internal_encoding();
439  
-			mb_internal_encoding($this->charset);
440  
-		}
441  
-		$return = mb_encode_mimeheader($subject, $this->charset, 'B', $nl);
442  
-		if ($internalEncoding) {
443  
-			mb_internal_encoding($restore);
444  
-		}
445  
-		return $return;
446  
-	}
447  
-
448  
-/**
449 424
  * Format addresses to be an array with email as key and alias as value
450 425
  *
451 426
  * @param array $addresses
@@ -455,7 +430,7 @@ protected function _formatAddresses($addresses) {
455 430
 		$formatted = array();
456 431
 		foreach ($addresses as $address) {
457 432
 			if (preg_match('/((.*))?\s?<(.+)>/', $address, $matches) && !empty($matches[2])) {
458  
-				$formatted[$this->_strip($matches[3])] = $this->_encode($matches[2]);
  433
+				$formatted[$this->_strip($matches[3])] = $matches[2];
459 434
 			} else {
460 435
 				$address = $this->_strip($address);
461 436
 				$formatted[$address] = $address;
29  lib/Cake/Model/Datasource/Database/Mysql.php
@@ -78,17 +78,6 @@ class Mysql extends DboSource {
78 78
 	protected $_useAlias = true;
79 79
 
80 80
 /**
81  
- * Index of basic SQL commands
82  
- *
83  
- * @var array
84  
- */
85  
-	protected $_commands = array(
86  
-		'begin'    => 'START TRANSACTION',
87  
-		'commit'   => 'COMMIT',
88  
-		'rollback' => 'ROLLBACK'
89  
-	);
90  
-
91  
-/**
92 81
  * List of engine specific additional field parameters used on table creating
93 82
  *
94 83
  * @var array
@@ -263,15 +252,6 @@ public function getEncoding() {
263 252
 	}
264 253
 
265 254
 /**
266  
- * Gets the version string of the database server
267  
- *
268  
- * @return string The database encoding
269  
- */
270  
-	public function getVersion() {
271  
-		return $this->_connection->getAttribute(PDO::ATTR_SERVER_VERSION);
272  
-	}
273  
-
274  
-/**
275 255
  * Query charset by collation
276 256
  *
277 257
  * @param string $name Collation name
@@ -696,4 +676,13 @@ public function getSchemaName() {
696 676
 		return $this->config['database'];
697 677
 	}
698 678
 
  679
+/**
  680
+ * Check if the server support nested transactions
  681
+ *
  682
+ * @return boolean
  683
+ */
  684
+	public function supportNestedTransaction() {
  685
+		return $this->nestedTransaction && version_compare($this->getVersion(), '4.1', '>=');
  686
+	}
  687
+
699 688
 }
20  lib/Cake/Model/Datasource/Database/Postgres.php
@@ -34,17 +34,6 @@ class Postgres extends DboSource {
34 34
 	public $description = "PostgreSQL DBO Driver";
35 35
 
36 36
 /**
37  
- * Index of basic SQL commands
38  
- *
39  
- * @var array
40  
- */
41  
-	protected $_commands = array(
42  
-		'begin'    => 'BEGIN',
43  
-		'commit'   => 'COMMIT',
44  
-		'rollback' => 'ROLLBACK'
45  
-	);
46  
-
47  
-/**
48 37
  * Base driver configuration settings.  Merged with user settings.
49 38
  *
50 39
  * @var array
@@ -906,4 +895,13 @@ public function getSchemaName() {
906 895
 		return $this->config['schema'];
907 896
 	}
908 897
 
  898
+/**
  899
+ * Check if the server support nested transactions
  900
+ *
  901
+ * @return boolean
  902
+ */
  903
+	public function supportNestedTransaction() {
  904
+		return $this->nestedTransaction && version_compare($this->getVersion(), '8.0', '>=');
  905
+	}
  906
+
909 907
 }
9  lib/Cake/Model/Datasource/Database/Sqlite.php
@@ -559,4 +559,13 @@ public function getSchemaName() {
559 559
 		return "main"; // Sqlite Datasource does not support multidb
560 560
 	}
561 561
 
  562
+/**
  563
+ * Check if the server support nested transactions
  564
+ *
  565
+ * @return boolean
  566
+ */
  567
+	public function supportNestedTransaction() {
  568
+		return $this->nestedTransaction && version_compare($this->getVersion(), '3.6.8', '>=');
  569
+	}
  570
+
562 571
 }
22  lib/Cake/Model/Datasource/Database/Sqlserver.php
@@ -99,31 +99,12 @@ class Sqlserver extends DboSource {
99 99
 	);
100 100
 
101 101
 /**
102  
- * Index of basic SQL commands
103  
- *
104  
- * @var array
105  
- */
106  
-	protected $_commands = array(
107  
-		'begin'    => 'BEGIN TRANSACTION',
108  
-		'commit'   => 'COMMIT',
109  
-		'rollback' => 'ROLLBACK'
110  
-	);
111  
-
112  
-/**
113 102
  * Magic column name used to provide pagination support for SQLServer 2008
114 103
  * which lacks proper limit/offset support.
115 104
  */
116 105
 	const ROW_COUNTER = '_cake_page_rownum_';
117 106
 
118 107
 /**
119  
- * The version of SQLServer being used.  If greater than 11
120  
- * Normal limit offset statements will be used
121  
- *
122  
- * @var string
123  
- */
124  
-	protected $_version;
125  
-
126  
-/**
127 108
  * Connects to the database using options in the given configuration array.
128 109
  *
129 110
  * @return boolean True if the database could be connected, else false
@@ -151,7 +132,6 @@ public function connect() {
151 132
 			throw new MissingConnectionException(array('class' => $e->getMessage()));
152 133
 		}
153 134
 
154  
-		$this->_version = $this->_connection->getAttribute(PDO::ATTR_SERVER_VERSION);
155 135
 		return $this->connected;
156 136
 	}
157 137
 
@@ -515,7 +495,7 @@ public function renderStatement($type, $data) {
515 495
 				}
516 496
 
517 497
 				// For older versions use the subquery version of pagination.
518  
-				if (version_compare($this->_version, '11', '<') && preg_match('/FETCH\sFIRST\s+([0-9]+)/i', $limit, $offset)) {
  498
+				if (version_compare($this->getVersion(), '11', '<') && preg_match('/FETCH\sFIRST\s+([0-9]+)/i', $limit, $offset)) {
519 499
 					preg_match('/OFFSET\s*(\d+)\s*.*?(\d+)\s*ROWS/', $limit, $limitOffset);
520 500
 
521 501
 					$limit = 'TOP ' . intval($limitOffset[2]);
142  lib/Cake/Model/Datasource/DboSource.php
@@ -70,6 +70,15 @@ class DboSource extends DataSource {
70 70
 	public $cacheMethods = true;
71 71
 
72 72
 /**
  73
+ * Flag to support nested transactions. If it is set to false, you will be able to use
  74
+ * the transaction methods (begin/commit/rollback), but just the global transaction will
  75
+ * be executed.
  76
+ *
  77
+ * @var boolean
  78
+ */
  79
+	public $nestedTransaction = true;
  80
+
  81
+/**
73 82
  * Print full query debug info?
74 83
  *
75 84
  * @var boolean
@@ -184,17 +193,6 @@ class DboSource extends DataSource {
184 193
 	protected $_transactionNesting = 0;
185 194
 
186 195
 /**
187  
- * Index of basic SQL commands
188  
- *
189  
- * @var array
190  
- */
191  
-	protected $_commands = array(
192  
-		'begin' => 'BEGIN',
193  
-		'commit' => 'COMMIT',
194  
-		'rollback' => 'ROLLBACK'
195  
-	);
196  
-
197  
-/**
198 196
  * Default fields that are used by the DBO
199 197
  *
200 198
  * @var array
@@ -294,13 +292,22 @@ public function disconnect() {
294 292
 /**
295 293
  * Get the underlying connection object.
296 294
  *
297  
- * @return PDOConnection
  295
+ * @return PDO
298 296
  */
299 297
 	public function getConnection() {
300 298
 		return $this->_connection;
301 299
 	}
302 300
 
303 301
 /**
  302
+ * Gets the version string of the database server
  303
+ *
  304
+ * @return string The database version
  305
+ */
  306
+	public function getVersion() {
  307
+		return $this->_connection->getAttribute(PDO::ATTR_SERVER_VERSION);
  308
+	}
  309
+
  310
+/**
304 311
  * Returns a quoted and escaped string of $data for use in an SQL statement.
305 312
  *
306 313
  * @param string $data String to be prepared for use in an SQL statement
@@ -2020,6 +2027,15 @@ public function truncate($table) {
2020 2027
 	}
2021 2028
 
2022 2029
 /**
  2030
+ * Check if the server support nested transactions
  2031
+ *
  2032
+ * @return boolean
  2033
+ */
  2034
+	public function supportNestedTransaction() {
  2035
+		return false;
  2036
+	}
  2037
+
  2038
+/**
2023 2039
  * Begin a transaction
2024 2040
  *
2025 2041
  * @return boolean True on success, false on fail
@@ -2027,15 +2043,33 @@ public function truncate($table) {
2027 2043
  * or a transaction has not started).
2028 2044
  */
2029 2045
 	public function begin() {
2030  
-		if ($this->_transactionStarted || $this->_connection->beginTransaction()) {
2031  
-			if ($this->fullDebug && empty($this->_transactionNesting)) {
2032  
-				$this->logQuery('BEGIN');
  2046
+		if ($this->_transactionStarted) {
  2047
+			if ($this->supportNestedTransaction()) {
  2048
+				return $this->_beginNested();
2033 2049
 			}
2034  
-			$this->_transactionStarted = true;
2035 2050
 			$this->_transactionNesting++;
2036  
-			return true;
  2051
+			return $this->_transactionStarted;
2037 2052
 		}
2038  
-		return false;
  2053
+
  2054
+		$this->_transactionNesting = 0;
  2055
+		if ($this->fullDebug) {
  2056
+			$this->logQuery('BEGIN');
  2057
+		}
  2058
+		return $this->_transactionStarted = $this->_connection->beginTransaction();
  2059
+	}
  2060
+
  2061
+/**
  2062
+ * Begin a nested transaction
  2063
+ *
  2064
+ * @return boolean
  2065
+ */
  2066
+	protected function _beginNested() {
  2067
+		$query = 'SAVEPOINT LEVEL' . ++$this->_transactionNesting;
  2068
+		if ($this->fullDebug) {
  2069
+			$this->logQuery($query);
  2070
+		}
  2071
+		$this->_connection->exec($query);
  2072
+		return true;
2039 2073
 	}
2040 2074
 
2041 2075
 /**
@@ -2046,19 +2080,38 @@ public function begin() {
2046 2080
  * or a transaction has not started).
2047 2081
  */
2048 2082
 	public function commit() {
2049  
-		if ($this->_transactionStarted) {
2050  
-			$this->_transactionNesting--;
2051  
-			if ($this->_transactionNesting <= 0) {
2052  
-				$this->_transactionStarted = false;
2053  
-				$this->_transactionNesting = 0;
2054  
-				if ($this->fullDebug) {
2055  
-					$this->logQuery('COMMIT');
2056  
-				}
2057  
-				return $this->_connection->commit();
  2083
+		if (!$this->_transactionStarted) {
  2084
+			return false;
  2085
+		}
  2086
+
  2087
+		if ($this->_transactionNesting === 0) {
  2088
+			if ($this->fullDebug) {
  2089
+				$this->logQuery('COMMIT');
2058 2090
 			}
2059  
-			return true;
  2091
+			$this->_transactionStarted = false;
  2092
+			return $this->_connection->commit();
2060 2093
 		}
2061  
-		return false;
  2094
+
  2095
+		if ($this->supportNestedTransaction()) {
  2096
+			return $this->_commitNested();
  2097
+		}
  2098
+
  2099
+		$this->_transactionNesting--;
  2100
+		return true;
  2101
+	}
  2102
+
  2103
+/**
  2104
+ * Commit a nested transaction
  2105
+ *
  2106
+ * @return boolean
  2107
+ */
  2108
+	protected function _commitNested() {
  2109
+		$query = 'RELEASE SAVEPOINT LEVEL' . $this->_transactionNesting--;
  2110
+		if ($this->fullDebug) {
  2111
+			$this->logQuery($query);
  2112
+		}
  2113
+		$this->_connection->exec($query);
  2114
+		return true;
2062 2115
 	}
2063 2116
 
2064 2117
 /**
@@ -2069,15 +2122,38 @@ public function commit() {
2069 2122
  * or a transaction has not started).
2070 2123
  */
2071 2124
 	public function rollback() {
2072  
-		if ($this->_transactionStarted && $this->_connection->rollBack()) {
  2125
+		if (!$this->_transactionStarted) {
  2126
+			return false;
  2127
+		}
  2128
+
  2129
+		if ($this->_transactionNesting === 0) {
2073 2130
 			if ($this->fullDebug) {
2074 2131
 				$this->logQuery('ROLLBACK');
2075 2132
 			}
2076 2133
 			$this->_transactionStarted = false;
2077  
-			$this->_transactionNesting = 0;
2078  
-			return true;
  2134
+			return $this->_connection->rollBack();
2079 2135
 		}
2080  
-		return false;
  2136
+
  2137
+		if ($this->supportNestedTransaction()) {
  2138
+			return $this->_rollbackNested();
  2139
+		}
  2140
+
  2141
+		$this->_transactionNesting--;
  2142
+		return true;
  2143
+	}
  2144
+
  2145
+/**
  2146
+ * Rollback a nested transaction
  2147
+ *
  2148
+ * @return boolean
  2149
+ */
  2150
+	protected function _rollbackNested() {
  2151
+		$query = 'ROLLBACK TO SAVEPOINT LEVEL' . $this->_transactionNesting--;
  2152
+		if ($this->fullDebug) {
  2153
+			$this->logQuery($query);
  2154
+		}
  2155
+		$this->_connection->exec($query);
  2156
+		return true;
2081 2157
 	}
2082 2158
 
2083 2159
 /**
2  lib/Cake/Model/Model.php
@@ -1629,7 +1629,7 @@ public function save($data = null, $validate = true, $fieldList = array()) {
1629 1629
 				if (!array_key_exists('format', $colType)) {
1630 1630
 					$time = strtotime('now');
1631 1631
 				} else {
1632  
-					$time = $colType['formatter']($colType['format']);
  1632
+					$time = call_user_func($colType['formatter'], $colType['format']);
1633 1633
 				}
1634 1634
 				if (!empty($this->whitelist)) {
1635 1635
 					$this->whitelist[] = $updateCol;
40  lib/Cake/Network/CakeRequest.php
@@ -320,21 +320,31 @@ protected function _processFiles() {
320 320
 
321 321
 		if (isset($_FILES['data'])) {
322 322
 			foreach ($_FILES['data'] as $key => $data) {
323  
-				foreach ($data as $model => $fields) {
324  
-					if (is_array($fields)) {
325  
-						foreach ($fields as $field => $value) {
326  
-							if (is_array($value)) {
327  
-								foreach ($value as $k => $v) {
328  
-									$this->data[$model][$field][$k][$key] = $v;
329  
-								}
330  
-							} else {
331  
-								$this->data[$model][$field][$key] = $value;
332  
-							}
333  
-						}
334  
-					} else {
335  
-						$this->data[$model][$key] = $fields;
336  
-					}
337  
-				}
  323
+				$this->_processFileData('', $data, $key);
  324
+			}
  325
+		}
  326
+	}
  327
+
  328
+/**
  329
+ * Recursively walks the FILES array restructuring the data
  330
+ * into something sane and useable.
  331
+ *
  332
+ * @param string $path The dot separated path to insert $data into.
  333
+ * @param array $data The data to traverse/insert.
  334
+ * @param string $field The terminal field name, which is the top level key in $_FILES.
  335
+ * @return void
  336
+ */
  337
+	protected function _processFileData($path, $data, $field) {
  338
+		foreach ($data as $key => $fields) {
  339
+			$newPath = $key;
  340
+			if (!empty($path)) {
  341
+				$newPath = $path . '.' . $key;
  342
+			}
  343
+			if (is_array($fields)) {
  344
+				$this->_processFileData($newPath, $fields, $field);
  345
+			} else {
  346
+				$newPath .= '.' . $field;
  347
+				$this->data = Set::insert($this->data, $newPath, $fields);
338 348
 			}
339 349
 		}
340 350
 	}
9  lib/Cake/Routing/Dispatcher.php
@@ -44,7 +44,7 @@ class Dispatcher implements CakeEventListener {
44 44
  * Event manager, used to handle dispatcher filters
45 45
  *
46 46
  * @var CakeEventMaanger
47  
- **/
  47
+ */
48 48
 	protected $_eventManager;
49 49
 
50 50
 /**
@@ -63,7 +63,7 @@ public function __construct($base = false) {
63 63
  * creted. Attaches the default listeners and filters
64 64
  *
65 65
  * @return CakeEventmanger
66  
- **/
  66
+ */
67 67
 	public function getEventManager() {
68 68
 		if (!$this->_eventManager) {
69 69
 			$this->_eventManager = new CakeEventManager();
@@ -77,7 +77,7 @@ public function getEventManager() {
77 77
  * Returns the list of events this object listents to.
78 78
  *
79 79
  * @return array
80  
- **/
  80
+ */
81 81
 	public function implementedEvents() {
82 82
 		return array('Dispatcher.beforeDispatch' => 'parseParams');
83 83
 	}
@@ -88,7 +88,8 @@ public function implementedEvents() {
88 88
  *
89 89
  * @param CakeEventManager $manager
90 90
  * @return void
91  
- **/
  91
+ * @throws MissingDispatcherFilterException
  92
+ */
92 93
 	protected function _attachFilters($manager) {
93 94
 		$filters = Configure::read('Dispatcher.filters');
94 95
 		if (empty($filters)) {
16  lib/Cake/Routing/Filter/CacheDispatcher.php
... ...
@@ -1,19 +1,15 @@
1 1
 <?php
2 2
 /**
3  
- *
4  
- * PHP 5
5  
- *
6 3
  * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
7 4
  * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
8 5
  *
9 6
  * Licensed under The MIT License
10 7
  * Redistributions of files must retain the above copyright notice.
11 8
  *
12  
- * @copyright	  Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
13  
- * @link		  http://cakephp.org CakePHP(tm) Project
14  
- * @package		  Cake.Routing
15  
- * @since		  CakePHP(tm) v 2.2
16  
- * @license		  MIT License (http://www.opensource.org/licenses/mit-license.php)
  9
+ * @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
  10
+ * @link http://cakephp.org CakePHP(tm) Project
  11
+ * @since CakePHP(tm) v 2.2
  12
+ * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
17 13
  */
18 14
 
19 15
 App::uses('DispatcherFilter', 'Routing');
@@ -31,7 +27,7 @@ class CacheDispatcher extends DispatcherFilter {
31 27
  * This filter should run before the request gets parsed by router
32 28
  *
33 29
  * @var int
34  
- **/
  30
+ */
35 31
 	public $priority = 9;
36 32
 
37 33
 /**
@@ -68,4 +64,4 @@ public function beforeDispatch($event) {
68 64
 		}
69 65
 	}
70 66
 
71  
-}
  67
+}
3  lib/Cake/Routing/Router.php
@@ -1014,7 +1014,8 @@ public static function reverse($params, $full = false) {
1014 1014
 	public static function normalize($url = '/') {
1015 1015
 		if (is_array($url)) {
1016 1016
 			$url = Router::url($url);
1017  
-		} elseif (preg_match('/^[a-z\-]+:\/\//', $url)) {
  1017
+		}
  1018
+		if (preg_match('/^[a-z\-]+:\/\//', $url)) {
1018 1019
 			return $url;
1019 1020
 		}
1020 1021
 		$request = Router::getRequest();
2  lib/Cake/Test/Case/Cache/Engine/FileEngineTest.php
@@ -410,7 +410,7 @@ public function testGroupsReadWrite() {
410 410
 		$this->assertTrue(Cache::write('test_groups3', 'value3', 'file_groups'));
411 411
 	}
412 412
 
413  
-	/**
  413
+/**
414 414
  * Tests that deleteing from a groups-enabled config is possible
415 415
  *
416 416
  * @return void
3  lib/Cake/Test/Case/Cache/Engine/RedisEngineTest.php
@@ -220,7 +220,6 @@ public function testIncrement() {
220 220
 		$this->assertEquals(3, $result);
221 221
 	}
222 222
 
223  
-
224 223
 /**
225 224
  * test clearing redis.
226 225
  *
@@ -333,4 +332,4 @@ public function testGroupClear() {
333 332
 		$this->assertFalse(Cache::read('test_groups', 'redis_groups'));
334 333
 	}
335 334
 
336  
-}
  335
+}
3  lib/Cake/Test/Case/Controller/Component/Auth/FormAuthenticateTest.php
@@ -163,7 +163,6 @@ public function testPluginModel() {
163 163
 		), App::RESET);
164 164
 		CakePlugin::load('TestPlugin');
165 165
 
166  
-		$ts = date('Y-m-d H:i:s');
167 166
 		$PluginModel = ClassRegistry::init('TestPlugin.TestPluginAuthUser');
168 167
 		$user['id'] = 1;
169 168
 		$user['username'] = 'gwoo';
@@ -185,7 +184,7 @@ public function testPluginModel() {
185 184
 			'username' => 'gwoo',
186 185
 			'created' => '2007-03-17 01:16:23'
187 186
 		);
188  
-		$this->assertTrue($result['updated'] >= $ts);
  187
+		$this->assertEquals(self::date(), $result['updated']);
189 188
 		unset($result['updated']);
190 189
 		$this->assertEquals($expected, $result);
191 190
 		CakePlugin::unload();
18  lib/Cake/Test/Case/Controller/Component/EmailComponentTest.php
@@ -868,4 +868,22 @@ public function testMessageId() {
868 868
 		$this->assertNotRegExp('/Message-ID:/', $result);
869 869
 	}
870 870
 
  871
+/**
  872
+ * Make sure from/to are not double encoded when UTF-8 is present
  873
+ */
  874
+	public function testEncodingFrom() {
  875
+		$this->Controller->EmailTest->to = 'Teßt <test@example.com>';
  876
+		$this->Controller->EmailTest->from = 'Teßt <test@example.com>';
  877
+		$this->Controller->EmailTest->subject = 'Cake Debug Test';
  878
+		$this->Controller->EmailTest->replyTo = 'noreply@example.com';
  879
+		$this->Controller->EmailTest->template = null;
  880
+
  881
+		$this->Controller->EmailTest->delivery = 'DebugComp';
  882
+		$this->assertTrue($this->Controller->EmailTest->send('This is the body of the message'));
  883
+		$result = DebugCompTransport::$lastEmail;
  884
+
  885
+		$this->assertContains('From: =?UTF-8?B?VGXDn3Qg?= <test@example.com>', $result);
  886
+		$this->assertContains('To: =?UTF-8?B?VGXDn3Qg?= <test@example.com>', $result);
  887
+	}
  888
+
871 889
 }
36  lib/Cake/Test/Case/Model/Datasource/Database/MysqlTest.php
@@ -45,7 +45,7 @@ class MysqlTest extends CakeTestCase {
45 45
 	public $fixtures = array(
46 46
 		'core.apple', 'core.article', 'core.articles_tag', 'core.attachment', 'core.comment',
47 47
 		'core.sample', 'core.tag', 'core.user', 'core.post', 'core.author', 'core.data_test',
48  
-		'core.binary_test'
  48
+		'core.binary_test', 'app.address'
49 49
 	);
50 50
 
51 51
 /**
@@ -3579,4 +3579,38 @@ public function testTruncateStatements() {
3579 3579
 			->with("TRUNCATE TABLE `$schema`.`tbl_articles`");
3580 3580
 		$this->Dbo->truncate('articles');
3581 3581
 	}
  3582
+
  3583
+/**
  3584
+ * Test nested transaction
  3585
+ *
  3586
+ * @return void
  3587
+ */
  3588
+	public function testNestedTransaction() {
  3589
+		$this->skipIf($this->Dbo->supportNestedTransaction() === false, 'The MySQL server do not support nested transaction');
  3590
+
  3591
+		$this->loadFixtures('Address');
  3592
+		$model = ClassRegistry::init('Address');
  3593
+		$model->hasOne = $model->hasMany = $model->belongsTo = $model->hasAndBelongsToMany = array();
  3594
+		$model->cacheQueries = false;
  3595
+		$this->Dbo->cacheMethods = false;
  3596
+
  3597
+		$this->assertTrue($this->Dbo->begin());
  3598
+		$this->assertNotEmpty($model->read(null, 1));
  3599
+
  3600
+		$this->assertTrue($this->Dbo->begin());
  3601
+		$this->assertTrue($model->delete(1));
  3602
+		$this->assertEmpty($model->read(null, 1));
  3603
+		$this->assertTrue($this->Dbo->rollback());
  3604
+		$this->assertNotEmpty($model->read(null, 1));
  3605
+
  3606
+		$this->assertTrue($this->Dbo->begin());
  3607
+		$this->assertTrue($model->delete(1));
  3608
+		$this->assertEmpty($model->read(null, 1));
  3609
+		$this->assertTrue($this->Dbo->commit());
  3610
+		$this->assertEmpty($model->read(null, 1));
  3611
+
  3612
+		$this->assertTrue($this->Dbo->rollback());
  3613
+		$this->assertNotEmpty($model->read(null, 1));
  3614
+	}
  3615
+
3582 3616
 }
33  lib/Cake/Test/Case/Model/Datasource/Database/PostgresTest.php
@@ -909,4 +909,37 @@ public function testTruncateStatements() {
909 909
 		$this->Dbo->truncate('articles');
910 910
 	}
911 911
 
  912
+/**
  913
+ * Test nested transaction
  914
+ *
  915
+ * @return void
  916
+ */
  917
+	public function testNestedTransaction() {
  918
+		$this->skipIf($this->Dbo->supportNestedTransaction() === false, 'The Postgres server do not support nested transaction');
  919
+
  920
+		$this->loadFixtures('Article');
  921
+		$model = new Article();
  922
+		$model->hasOne = $model->hasMany = $model->belongsTo = $model->hasAndBelongsToMany = array();
  923
+		$model->cacheQueries = false;
  924
+		$this->Dbo->cacheMethods = false;
  925
+
  926
+		$this->assertTrue($this->Dbo->begin());
  927
+		$this->assertNotEmpty($model->read(null, 1));
  928
+
  929
+		$this->assertTrue($this->Dbo->begin());
  930
+		$this->assertTrue($model->delete(1));
  931
+		$this->assertEmpty($model->read(null, 1));
  932
+		$this->assertTrue($this->Dbo->rollback());
  933
+		$this->assertNotEmpty($model->read(null, 1));
  934
+
  935
+		$this->assertTrue($this->Dbo->begin());
  936
+		$this->assertTrue($model->delete(1));
  937
+		$this->assertEmpty($model->read(null, 1));
  938
+		$this->assertTrue($this->Dbo->commit());
  939
+		$this->assertEmpty($model->read(null, 1));
  940
+
  941
+		$this->assertTrue($this->Dbo->rollback());
  942
+		$this->assertNotEmpty($model->read(null, 1));
  943
+	}
  944
+
912 945
 }
33  lib/Cake/Test/Case/Model/Datasource/Database/SqliteTest.php
@@ -383,4 +383,37 @@ public function testUuidPrimaryKeyInsertion() {
383 383
 		$this->assertTrue(Validation::uuid($result['Uuid']['id']), 'Not a uuid');
384 384
 	}
385 385
 
  386
+/**
  387
+ * Test nested transaction
  388
+ *
  389
+ * @return void
  390
+ */
  391
+	public function testNestedTransaction() {
  392
+		$this->skipIf($this->Dbo->supportNestedTransaction() === false, 'The Sqlite version do not support nested transaction');
  393
+
  394
+		$this->loadFixtures('User');
  395
+		$model = new User();
  396
+		$model->hasOne = $model->hasMany = $model->belongsTo = $model->hasAndBelongsToMany = array();
  397
+		$model->cacheQueries = false;
  398
+		$this->Dbo->cacheMethods = false;
  399
+
  400
+		$this->assertTrue($this->Dbo->begin());
  401
+		$this->assertNotEmpty($model->read(null, 1));
  402
+
  403
+		$this->assertTrue($this->Dbo->begin());
  404
+		$this->assertTrue($model->delete(1));
  405
+		$this->assertEmpty($model->read(null, 1));
  406
+		$this->assertTrue($this->Dbo->rollback());
  407
+		$this->assertNotEmpty($model->read(null, 1));
  408
+
  409
+		$this->assertTrue($this->Dbo->begin());
  410
+		$this->assertTrue($model->delete(1));
  411
+		$this->assertEmpty($model->read(null, 1));
  412
+		$this->assertTrue($this->Dbo->commit());
  413
+		$this->assertEmpty($model->read(null, 1));
  414
+
  415
+		$this->assertTrue($this->Dbo->rollback());
  416
+		$this->assertNotEmpty($model->read(null, 1));
  417
+	}
  418
+
386 419
 }
79  lib/Cake/Test/Case/Model/Datasource/DboSourceTest.php
@@ -35,6 +35,8 @@ class MockDataSource extends DataSource {
35 35
 
36 36
 class DboTestSource extends DboSource {
37 37
 
  38
+	public static $nested = true;
  39
+
38 40
 	public function connect($config = array()) {
39 41
 		$this->connected = true;
40 42
 	}
@@ -51,6 +53,10 @@ public function setConnection($conn) {
51 53
 		$this->_connection = $conn;
52 54
 	}
53 55
 
  56
+	public function supportNestedTransaction() {
  57
+		return $this->nestedTransaction && self::$nested;
  58
+	}
  59
+
54 60
 }
55 61
 
56 62
 /**
@@ -835,6 +841,79 @@ public function testTransactionLogging() {
835 841
 	}
836 842
 
837 843
 /**
  844
+ * Test nested transaction calls
  845
+ *
  846
+ * @return void
  847
+ */
  848
+	public function testTransactionNested() {
  849
+		$conn = $this->getMock('MockPDO');
  850
+		$db = new DboTestSource();
  851
+		$db->setConnection($conn);
  852
+		DboTestSource::$nested = true;
  853
+
  854
+		$conn->expects($this->at(0))->method('beginTransaction')->will($this->returnValue(true));
  855
+		$conn->expects($this->at(1))->method('exec')->with($this->equalTo('SAVEPOINT LEVEL1'))->will($this->returnValue(true));
  856
+		$conn->expects($this->at(2))->method('exec')->with($this->equalTo('RELEASE SAVEPOINT LEVEL1'))->will($this->returnValue(true));
  857
+		$conn->expects($this->at(3))->method('exec')->with($this->equalTo('SAVEPOINT LEVEL1'))->will($this->returnValue(true));
  858
+		$conn->expects($this->at(4))->method('exec')->with($this->equalTo('ROLLBACK TO SAVEPOINT LEVEL1'))->will($this->returnValue(true));
  859
+		$conn->expects($this->at(5))->method('commit')->will($this->returnValue(true));
  860
+
  861
+		$this->_runTransactions($db);
  862
+	}
  863
+
  864
+/**
  865
+ * Test nested transaction calls without support
  866
+ *
  867
+ * @return void
  868
+ */
  869
+	public function testTransactionNestedWithoutSupport() {
  870
+		$conn = $this->getMock('MockPDO');
  871
+		$db = new DboTestSource();
  872
+		$db->setConnection($conn);
  873
+		$db->nestedTransaction = false;
  874
+		DboTestSource::$nested = true;
  875
+
  876
+		$conn->expects($this->once())->method('beginTransaction')->will($this->returnValue(true));
  877
+		$conn->expects($this->never())->method('exec');
  878
+		$conn->expects($this->once())->method('commit')->will($this->returnValue(true));
  879
+
  880
+		$this->_runTransactions($db);
  881
+	}
  882
+
  883
+/**
  884
+ * Test nested transaction disabled
  885
+ *
  886
+ * @return void
  887
+ */
  888
+	public function testTransactionNestedDisabled() {
  889
+		$conn = $this->getMock('MockPDO');
  890
+		$db = new DboTestSource();
  891
+		$db->setConnection($conn);
  892
+		DboTestSource::$nested = false;
  893
+
  894
+		$conn->expects($this->once())->method('beginTransaction')->will($this->returnValue(true));
  895