Browse Source

Merge remote-tracking branch 'origin/2.7' into 3.0

Conflicts:
	VERSION.txt
	app/Config/database.php.default
	lib/Cake/Cache/Engine/MemcachedEngine.php
	lib/Cake/Model/Datasource/Database/Postgres.php
	lib/Cake/Model/Datasource/DboSource.php
	lib/Cake/Network/Http/HttpSocket.php
	lib/Cake/Network/Http/HttpSocketResponse.php
	lib/Cake/Test/Case/Model/Datasource/Database/MysqlTest.php
	lib/Cake/Test/Case/Network/Http/HttpResponseTest.php
	lib/Cake/Test/Case/Network/Http/HttpSocketTest.php
	lib/Cake/TestSuite/CakeTestRunner.php
	lib/Cake/TestSuite/CakeTestSuiteCommand.php
	lib/Cake/TestSuite/CakeTestSuiteDispatcher.php
	lib/Cake/TestSuite/Reporter/CakeBaseReporter.php
	lib/Cake/bootstrap.php
	src/Network/Request.php
	src/View/Helper/HtmlHelper.php
	tests/TestCase/Network/Email/EmailTest.php
Mark Story 11 years ago
parent
commit
e07eb45250

+ 5 - 2
src/Cache/Engine/MemcachedEngine.php

@@ -124,8 +124,11 @@ class MemcachedEngine extends CacheEngine {
 			return true;
 		}
 
-		$this->_Memcached = new Memcached($this->_config['persistent'] ?
-			(string)$this->_config['persistent'] : null);
+		if ($this->_config['persistent']) {
+			$this->_Memcached = new Memcached((string)$this->_config['persistent']);
+		} else {
+			$this->_Memcached = new Memecached();
+		}
 		$this->_setOptions();
 
 		if (count($this->_Memcached->getServerList())) {

+ 1 - 1
src/Network/Email/Email.php

@@ -1458,7 +1458,7 @@ class Email {
 		$cut = ($wrapLength == Email::LINE_LENGTH_MUST);
 
 		foreach ($lines as $line) {
-			if (empty($line)) {
+			if (empty($line) && $line !== '0') {
 				$formatted[] = '';
 				continue;
 			}

+ 94 - 14
src/Network/Request.php

@@ -129,7 +129,9 @@ class Request implements \ArrayAccess {
 		'ssl' => array('env' => 'HTTPS', 'options' => [1, 'on']),
 		'ajax' => array('env' => 'HTTP_X_REQUESTED_WITH', 'value' => 'XMLHttpRequest'),
 		'flash' => array('env' => 'HTTP_USER_AGENT', 'pattern' => '/^(Shockwave|Adobe) Flash/'),
-		'requested' => array('param' => 'requested', 'value' => 1)
+		'requested' => array('param' => 'requested', 'value' => 1),
+		'json' => array('accept' => array('application/json'), 'param' => '_ext', 'value' => 'json'),
+		'xml' => array('accept' => array('application/xml', 'text/xml'), 'param' => '_ext', 'value' => 'xml'),
 	);
 
 /**
@@ -621,6 +623,97 @@ class Request implements \ArrayAccess {
 		if (is_callable($detect)) {
 			return call_user_func($detect, $this);
 		}
+		if (isset($detect['env']) && $this->_environmentDetector($detect)) {
+			return true;
+		}
+		if (isset($detect['header']) && $this->_headerDetector($detect)) {
+			return true;
+		}
+		if (isset($detect['accept']) && $this->_acceptHeaderDetector($detect)) {
+			return true;
+		}
+		if (isset($detect['param']) && $this->_paramDetector($detect)) {
+			return true;
+		}
+		return false;
+	}
+
+/**
+ * Detects if a URL extension is present.
+ *
+ * @param array $detect Detector options array.
+ * @return bool Whether or not the request is the type you are checking.
+ */
+	protected function _extensionDetector($detect) {
+		if (is_string($detect['extension'])) {
+			$detect['extension'] = array($detect['extension']);
+		}
+		if (in_array($this->params['_ext'], $detect['extension'])) {
+			return true;
+		}
+		return false;
+	}
+
+/**
+ * Detects if a specific accept header is present.
+ *
+ * @param array $detect Detector options array.
+ * @return bool Whether or not the request is the type you are checking.
+ */
+	protected function _acceptHeaderDetector($detect) {
+		$acceptHeaders = explode(',', $this->env('HTTP_ACCEPT'));
+		foreach ($detect['accept'] as $header) {
+			if (in_array($header, $acceptHeaders)) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+/**
+ * Detects if a specific header is present.
+ *
+ * @param array $detect Detector options array.
+ * @return bool Whether or not the request is the type you are checking.
+ */
+	protected function _headerDetector($detect) {
+		foreach ($detect['header'] as $header => $value) {
+			$header = $this->env('http_' . $header);
+			if (!is_null($header)) {
+				if (!is_string($value) && !is_bool($value) && is_callable($value)) {
+					return call_user_func($value, $header);
+				}
+				return ($header === $value);
+			}
+		}
+		return false;
+	}
+
+/**
+ * Detects if a specific request parameter is present.
+ *
+ * @param array $detect Detector options array.
+ * @return bool Whether or not the request is the type you are checking.
+ */
+	protected function _paramDetector($detect) {
+		$key = $detect['param'];
+		if (isset($detect['value'])) {
+			$value = $detect['value'];
+			return isset($this->params[$key]) ? $this->params[$key] == $value : false;
+		}
+		if (isset($detect['options'])) {
+			return isset($this->params[$key]) ? in_array($this->params[$key], $detect['options']) : false;
+		}
+		return false;
+	}
+
+/**
+ * Detects if a specific environment variable is present.
+ *
+ * @param array $detect Detector options array.
+ * @return bool Whether or not the request is the type you are checking.
+ */
+	protected function _environmentDetector($detect) {
 		if (isset($detect['env'])) {
 			if (isset($detect['value'])) {
 				return $this->env($detect['env']) == $detect['value'];
@@ -633,19 +726,6 @@ class Request implements \ArrayAccess {
 				return (bool)preg_match($pattern, $this->env($detect['env']));
 			}
 		}
-		if (isset($detect['param'])) {
-			$key = $detect['param'];
-			if (isset($detect['value'])) {
-				$value = $detect['value'];
-				return isset($this->params[$key]) ? $this->params[$key] == $value : false;
-			}
-			if (isset($detect['options'])) {
-				return isset($this->params[$key]) ? in_array($this->params[$key], $detect['options']) : false;
-			}
-		}
-		if (isset($detect['callback']) && is_callable($detect['callback'])) {
-			return call_user_func($detect['callback'], $this);
-		}
 		return false;
 	}
 

+ 3 - 1
src/Network/Response.php

@@ -1520,7 +1520,9 @@ class Response {
 	protected function _flushBuffer() {
 		//@codingStandardsIgnoreStart
 		@flush();
-		@ob_flush();
+		if (ob_get_level()) {
+			@ob_flush();
+		}
 		//@codingStandardsIgnoreEnd
 	}
 

+ 5 - 5
src/View/Helper/HtmlHelper.php

@@ -418,11 +418,11 @@ class HtmlHelper extends Helper {
 			$options = array_diff_key($options, array('fullBase' => null, 'pathPrefix' => null));
 		}
 
-		if ($options['once'] && isset($this->_includedAssets[$url])) {
+		if ($options['once'] && isset($this->_includedAssets[__METHOD__][$path])) {
 			return '';
 		}
 		unset($options['once']);
-		$this->_includedAssets[$url] = true;
+		$this->_includedAssets[__METHOD__][$path] = true;
 		$templater = $this->templater();
 
 		if ($options['rel'] === 'import') {
@@ -501,11 +501,11 @@ class HtmlHelper extends Helper {
 			$url = $this->Url->assetUrl($url, $options + array('pathPrefix' => Configure::read('App.jsBaseUrl'), 'ext' => '.js'));
 			$options = array_diff_key($options, array('fullBase' => null, 'pathPrefix' => null));
 		}
-
-		if ($options['once'] && isset($this->_includedAssets[$url])) {
+		if ($options['once'] && isset($this->_includedAssets[__METHOD__][$url])) {
 			return null;
 		}
-		$this->_includedAssets[$url] = true;
+		$this->_includedAssets[__METHOD__][$url] = true;
+
 
 		$out = $this->formatTemplate('javascriptlink', [
 			'url' => $url,

+ 18 - 0
tests/TestCase/Network/Email/EmailTest.php

@@ -2477,6 +2477,24 @@ HTML;
 	}
 
 /**
+ * testZeroOnlyLinesNotBeingEmptied()
+ *
+ * @return void
+ */
+	public function testZeroOnlyLinesNotBeingEmptied() {
+		$message = "Lorem\r\n0\r\n0\r\nipsum";
+
+		$this->CakeEmail->reset();
+		$this->CakeEmail->transport('debug');
+		$this->CakeEmail->from('cake@cakephp.org');
+		$this->CakeEmail->to('cake@cakephp.org');
+		$this->CakeEmail->subject('Wordwrap Test');
+		$result = $this->CakeEmail->send($message);
+		$expected = "{$message}\r\n\r\n";
+		$this->assertEquals($expected, $result['message']);
+	}
+
+/**
  * CakeEmailTest::assertLineLengths()
  *
  * @param string $message

+ 69 - 13
tests/TestCase/Network/RequestTest.php

@@ -57,6 +57,52 @@ class RequestTest extends TestCase {
 	}
 
 /**
+ * Test the header detector.
+ *
+ * @return void
+ */
+	public function testHeaderDetector() {
+		$request = new Request();
+		$request->addDetector('host', array('header' => array('host' => 'cakephp.org')));
+
+		$request->env('HTTP_HOST', 'cakephp.org');
+		$this->assertTrue($request->is('host'));
+
+		$request->env('HTTP_HOST', 'php.net');
+		$this->assertFalse($request->is('host'));
+	}
+
+/**
+ * Test the accept header detector.
+ *
+ * @return void
+ */
+	public function testExtensionDetector() {
+		$request = new Request();
+		$request->params['_ext'] = 'json';
+		$this->assertTrue($request->is('json'));
+
+		$request = new Request();
+		$request->params['_ext'] = 'xml';
+		$this->assertFalse($request->is('json'));
+	}
+
+/**
+ * Test the accept header detector.
+ *
+ * @return void
+ */
+	public function testAcceptHeaderDetector() {
+		$request = new Request();
+		$request->env('HTTP_ACCEPT', 'application/json, text/plain, */*');
+		$this->assertTrue($request->is('json'));
+
+		$request = new Request();
+		$request->env('HTTP_ACCEPT', 'text/plain, */*');
+		$this->assertFalse($request->is('json'));
+	}
+
+/**
  * Test that the autoparse = false constructor works.
  *
  * @return void
@@ -536,6 +582,25 @@ class RequestTest extends TestCase {
 	}
 
 /**
+ * Test is() with json and xml.
+ *
+ * @return void
+ */
+	public function testIsJsonAndXml() {
+		$request = new Request();
+		$request->env('HTTP_ACCEPT', 'application/json, text/plain, */*');
+		$this->assertTrue($request->is('json'));
+
+		$request = new Request();
+		$request->env('HTTP_ACCEPT', 'application/xml, text/plain, */*');
+		$this->assertTrue($request->is('xml'));
+
+		$request = new Request();
+		$request->env('HTTP_ACCEPT', 'text/xml, */*');
+		$this->assertTrue($request->is('xml'));
+	}
+
+/**
  * Test is() with multiple types.
  *
  * @return void
@@ -843,9 +908,8 @@ class RequestTest extends TestCase {
 		$request->env('HTTP_USER_AGENT', 'Imagination land');
 		$this->assertTrue($request->isMobile());
 
-		Request::addDetector('callme', array('env' => 'TEST_VAR', 'callback' => array($this, 'detectCallback')));
-
 		Request::addDetector('index', array('param' => 'action', 'value' => 'index'));
+
 		$request->params['action'] = 'index';
 		$request->clearDetectorCache();
 		$this->assertTrue($request->isIndex());
@@ -854,25 +918,17 @@ class RequestTest extends TestCase {
 		$request->clearDetectorCache();
 		$this->assertFalse($request->isIndex());
 
-		$request->return = true;
-		$request->clearDetectorCache();
-		$this->assertTrue($request->isCallMe());
-
-		$request->return = false;
-		$request->clearDetectorCache();
-		$this->assertFalse($request->isCallMe());
-
 		Request::addDetector('callme', array($this, 'detectCallback'));
 		$request->return = true;
 		$request->clearDetectorCache();
 		$this->assertTrue($request->isCallMe());
 
-		Request::addDetector('extension', array('param' => 'ext', 'options' => array('pdf', 'png', 'txt')));
-		$request->params['ext'] = 'pdf';
+		Request::addDetector('extension', array('param' => '_ext', 'options' => array('pdf', 'png', 'txt')));
+		$request->params['_ext'] = 'pdf';
 		$request->clearDetectorCache();
 		$this->assertTrue($request->is('extension'));
 
-		$request->params['ext'] = 'exe';
+		$request->params['_ext'] = 'exe';
 		$request->clearDetectorCache();
 		$this->assertFalse($request->isExtension());
 	}

+ 16 - 0
tests/TestCase/View/Helper/HtmlHelperTest.php

@@ -752,6 +752,22 @@ class HtmlHelperTest extends TestCase {
 	}
 
 /**
+ * Resource names must be treated differently for css() and script()
+ *
+ * @return void
+ */
+	public function testBufferedCssAndScriptWithIdenticalResourceName() {
+		$this->View->expects($this->at(0))
+			->method('append')
+			->with('css', $this->stringContains('test.min.css'));
+		$this->View->expects($this->at(1))
+			->method('append')
+			->with('script', $this->stringContains('test.min.js'));
+		$this->Html->css('test.min', array('inline' => false));
+		$this->Html->script('test.min', array('inline' => false));
+	}
+
+/**
  * test timestamp enforcement for script tags.
  *
  * @return void