diff --git a/lib/Cake/Controller/Component/Auth/BaseAuthenticate.php b/lib/Cake/Controller/Component/Auth/BaseAuthenticate.php index 6541a15e3..65a0b80d3 100644 --- a/lib/Cake/Controller/Component/Auth/BaseAuthenticate.php +++ b/lib/Cake/Controller/Component/Auth/BaseAuthenticate.php @@ -1,7 +1,5 @@ passwordHasher()->check($password, $user[$fields['password']])) { return false; } diff --git a/lib/Cake/Event/CakeEventManager.php b/lib/Cake/Event/CakeEventManager.php index 720855425..007ef521f 100644 --- a/lib/Cake/Event/CakeEventManager.php +++ b/lib/Cake/Event/CakeEventManager.php @@ -122,7 +122,7 @@ class CakeEventManager { * @return void */ protected function _attachSubscriber(CakeEventListener $subscriber) { - foreach ($subscriber->implementedEvents() as $eventKey => $function) { + foreach ((array)$subscriber->implementedEvents() as $eventKey => $function) { $options = array(); $method = $function; if (is_array($function) && isset($function['callable'])) { @@ -197,7 +197,7 @@ class CakeEventManager { * @return void */ protected function _detachSubscriber(CakeEventListener $subscriber, $eventKey = null) { - $events = $subscriber->implementedEvents(); + $events = (array)$subscriber->implementedEvents(); if (!empty($eventKey) && empty($events[$eventKey])) { return; } elseif (!empty($eventKey)) { diff --git a/lib/Cake/Model/Model.php b/lib/Cake/Model/Model.php index e865e7f2d..77db37047 100644 --- a/lib/Cake/Model/Model.php +++ b/lib/Cake/Model/Model.php @@ -2701,7 +2701,8 @@ class Model extends Object implements CakeEventListener { } $ids = $this->find('all', array_merge(array( - 'fields' => "{$this->alias}.{$this->primaryKey}", + 'fields' => "DISTINCT {$this->alias}.{$this->primaryKey}", + 'order' => false, 'recursive' => 0), compact('conditions')) ); diff --git a/lib/Cake/Routing/Router.php b/lib/Cake/Routing/Router.php index 9749e8240..2d3c4a622 100644 --- a/lib/Cake/Routing/Router.php +++ b/lib/Cake/Routing/Router.php @@ -506,6 +506,12 @@ class Router { $prefix = $options['prefix']; $connectOptions = $options['connectOptions']; unset($options['connectOptions']); + if (strpos($prefix, '/') !== 0) { + $prefix = '/' . $prefix; + } + if (substr($prefix, -1) !== '/') { + $prefix .= '/'; + } foreach ((array)$controller as $name) { list($plugin, $name) = pluginSplit($name); diff --git a/lib/Cake/Test/Case/Controller/Component/Auth/FormAuthenticateTest.php b/lib/Cake/Test/Case/Controller/Component/Auth/FormAuthenticateTest.php index deacfdec2..90f5797c9 100644 --- a/lib/Cake/Test/Case/Controller/Component/Auth/FormAuthenticateTest.php +++ b/lib/Cake/Test/Case/Controller/Component/Auth/FormAuthenticateTest.php @@ -118,6 +118,40 @@ class FormAuthenticateTest extends CakeTestCase { $this->assertFalse($this->auth->authenticate($request, $this->response)); } +/** + * Test for password as empty string with _checkFields() call skipped + * Refs https://github.com/cakephp/cakephp/pull/2441 + * + * @return void + */ + public function testAuthenticatePasswordIsEmptyString() { + $request = new CakeRequest('posts/index', false); + $request->data = array( + 'User' => array( + 'user' => 'mariano', + 'password' => '' + )); + + $this->auth = $this->getMock( + 'FormAuthenticate', + array('_checkFields'), + array( + $this->Collection, + array( + 'fields' => array('username' => 'user', 'password' => 'password'), + 'userModel' => 'User' + ) + ) + ); + + // Simulate that check for ensuring password is not empty is missing. + $this->auth->expects($this->once()) + ->method('_checkFields') + ->will($this->returnValue(true)); + + $this->assertFalse($this->auth->authenticate($request, $this->response)); + } + /** * test authenticate field is not string * diff --git a/lib/Cake/Test/Case/Model/ModelDeleteTest.php b/lib/Cake/Test/Case/Model/ModelDeleteTest.php index 5cadf2cfa..dc8f3107a 100644 --- a/lib/Cake/Test/Case/Model/ModelDeleteTest.php +++ b/lib/Cake/Test/Case/Model/ModelDeleteTest.php @@ -454,6 +454,70 @@ class ModelDeleteTest extends BaseModelTest { $this->assertFalse($result); } +/** + * testDeleteAllMultipleRowsPerId method + * + * Ensure find done in deleteAll only returns distinct ids. A wacky combination + * of association and conditions can sometimes generate multiple rows per id. + * + * @return void + */ + public function testDeleteAllMultipleRowsPerId() { + $this->loadFixtures('Article', 'User'); + + $TestModel = new Article(); + $TestModel->unbindModel(array( + 'belongsTo' => array('User'), + 'hasMany' => array('Comment'), + 'hasAndBelongsToMany' => array('Tag') + ), false); + $TestModel->bindModel(array( + 'belongsTo' => array( + 'User' => array( + 'foreignKey' => false, + 'conditions' => array( + 'Article.user_id = 1' + ) + ) + ) + ), false); + + $result = $TestModel->deleteAll( + array('Article.user_id' => array(1, 3)), + true, + true + ); + + $this->assertTrue($result); + } + +/** + * testDeleteAllWithOrderProperty + * + * Ensure find done in deleteAll works with models that has $order property set + * + * @return void + */ + public function testDeleteAllWithOrderProperty() { + $this->loadFixtures('Article', 'User'); + + $TestModel = new Article(); + $TestModel->order = 'Article.published desc'; + $TestModel->unbindModel(array( + 'belongsTo' => array('User'), + 'hasMany' => array('Comment'), + 'hasAndBelongsToMany' => array('Tag') + ), false); + + $result = $TestModel->deleteAll( + array('Article.user_id' => array(1, 3)), + true, + true + ); + + $this->assertTrue($result); + } + /** * testRecursiveDel method * diff --git a/lib/Cake/Test/Case/Model/ModelWriteTest.php b/lib/Cake/Test/Case/Model/ModelWriteTest.php index 0ef299814..3ad70fd84 100644 --- a/lib/Cake/Test/Case/Model/ModelWriteTest.php +++ b/lib/Cake/Test/Case/Model/ModelWriteTest.php @@ -6256,13 +6256,13 @@ class ModelWriteTest extends BaseModelTest { $TestModel->saveAssociated(array( 'Post' => array( - 'title' => $db->expression('(SELECT "Post with Author")'), + 'title' => $db->expression("(SELECT 'Post with Author')"), 'body' => 'This post will be saved with an author' ), 'Author' => array( 'user' => 'bob', 'password' => '5f4dcc3b5aa765d61d8327deb882cf90' - ))); + )), array('atomic' => false)); $result = $TestModel->find('first', array( 'order' => array('Post.id ' => 'DESC') diff --git a/lib/Cake/Test/Case/Routing/RouterTest.php b/lib/Cake/Test/Case/Routing/RouterTest.php index 582feb685..a58fb9f9c 100644 --- a/lib/Cake/Test/Case/Routing/RouterTest.php +++ b/lib/Cake/Test/Case/Routing/RouterTest.php @@ -237,6 +237,20 @@ class RouterTest extends CakeTestCase { ); $this->assertEquals($expected, $result); $this->assertEquals(array('test_plugin'), $resources); + + $resources = Router::mapResources('Posts', array('prefix' => 'api')); + + $_SERVER['REQUEST_METHOD'] = 'GET'; + $result = Router::parse('/api/posts'); + $expected = array( + 'pass' => array(), + 'named' => array(), + 'plugin' => null, + 'controller' => 'posts', + 'action' => 'index', + '[method]' => 'GET' + ); + $this->assertEquals($expected, $result); } /**