Skip to content
This repository
Browse code

Make Model::find('first') always return an array.

  • Loading branch information...
commit c741f60367be5bba21fb96f65ac220106148ceaa 1 parent 528671f
Ber Clausen authored October 25, 2012
15  lib/Cake/Model/Model.php
@@ -2613,9 +2613,12 @@ public function hasAny($conditions = null) {
2613 2613
  *
2614 2614
  *  Note: find(list) + database views have issues with MySQL 5.0. Try upgrading to MySQL 5.1 if you
2615 2615
  *  have issues with database views.
  2616
+ *
  2617
+ *  Note: find(count) has its own return values.
  2618
+ *
2616 2619
  * @param string $type Type of find operation (all / first / count / neighbors / list / threaded)
2617 2620
  * @param array $query Option fields (conditions / fields / joins / limit / offset / order / page / group / callbacks)
2618  
- * @return array Array of records
  2621
+ * @return array Array of records, or Null on failure.
2619 2622
  * @link http://book.cakephp.org/2.0/en/models/deleting-data.html#deleteall
2620 2623
  */
2621 2624
 	public function find($type = 'first', $query = array()) {
@@ -2638,10 +2641,10 @@ public function find($type = 'first', $query = array()) {
2638 2641
 
2639 2642
 		if ($type === 'all') {
2640 2643
 			return $results;
2641  
-		} else {
2642  
-			if ($this->findMethods[$type] === true) {
2643  
-				return $this->{'_find' . ucfirst($type)}('after', $query, $results);
2644  
-			}
  2644
+		}
  2645
+
  2646
+		if ($this->findMethods[$type] === true) {
  2647
+			return $this->{'_find' . ucfirst($type)}('after', $query, $results);
2645 2648
 		}
2646 2649
 	}
2647 2650
 
@@ -2707,7 +2710,7 @@ protected function _findFirst($state, $query, $results = array()) {
2707 2710
 			return $query;
2708 2711
 		} elseif ($state === 'after') {
2709 2712
 			if (empty($results[0])) {
2710  
-				return false;
  2713
+				return array();
2711 2714
 			}
2712 2715
 			return $results[0];
2713 2716
 		}
2  lib/Cake/Test/Case/Model/Behavior/TranslateBehaviorTest.php
@@ -422,7 +422,7 @@ public function testMissingTranslation() {
422 422
 		$TestModel = new TranslatedItem();
423 423
 		$TestModel->locale = 'rus';
424 424
 		$result = $TestModel->read(null, 1);
425  
-		$this->assertFalse($result);
  425
+		$this->assertEquals(array(), $result);
426 426
 
427 427
 		$TestModel->locale = array('rus');
428 428
 		$result = $TestModel->read(null, 1);
14  lib/Cake/Test/Case/Model/ModelDeleteTest.php
@@ -107,7 +107,7 @@ public function testDeleteHabtmReferenceWithConditions() {
107 107
 		$result = $Portfolio->find('first', array(
108 108
 			'conditions' => array('Portfolio.id' => 1)
109 109
 		));
110  
-		$this->assertFalse($result);
  110
+		$this->assertEquals(array(), $result);
111 111
 
112 112
 		$result = $Portfolio->ItemsPortfolio->find('all', array(
113 113
 			'conditions' => array('ItemsPortfolio.portfolio_id' => 1)
@@ -195,7 +195,7 @@ public function testDelete() {
195 195
 		$this->assertTrue($result);
196 196
 
197 197
 		$result = $TestModel->read(null, 2);
198  
-		$this->assertFalse($result);
  198
+		$this->assertEquals(array(), $result);
199 199
 
200 200
 		$TestModel->recursive = -1;
201 201
 		$result = $TestModel->find('all', array(
@@ -216,7 +216,7 @@ public function testDelete() {
216 216
 		$this->assertTrue($result);
217 217
 
218 218
 		$result = $TestModel->read(null, 3);
219  
-		$this->assertFalse($result);
  219
+		$this->assertEquals(array(), $result);
220 220
 
221 221
 		$TestModel->recursive = -1;
222 222
 		$result = $TestModel->find('all', array(
@@ -448,16 +448,16 @@ public function testRecursiveDel() {
448 448
 
449 449
 		$TestModel->recursive = 2;
450 450
 		$result = $TestModel->read(null, 2);
451  
-		$this->assertFalse($result);
  451
+		$this->assertEquals(array(), $result);
452 452
 
453 453
 		$result = $TestModel->Comment->read(null, 5);
454  
-		$this->assertFalse($result);
  454
+		$this->assertEquals(array(), $result);
455 455
 
456 456
 		$result = $TestModel->Comment->read(null, 6);
457  
-		$this->assertFalse($result);
  457
+		$this->assertEquals(array(), $result);
458 458
 
459 459
 		$result = $TestModel->Comment->Attachment->read(null, 1);
460  
-		$this->assertFalse($result);
  460
+		$this->assertEquals(array(), $result);
461 461
 
462 462
 		$result = $TestModel->find('count');
463 463
 		$this->assertEquals(2, $result);

8 notes on commit c741f60

Lars

$result = false;
$result['aa'] <-- would not produce any PHP Notice.

$result = array();
$result['aa'] <-- would produce a PHP Notice.

This is just an example of the advantage of false which should not occure anyway, because you'd check with isset().

I don't get this change. Why does $Model->find('first') should return an array instead of false?

José Lorenzo Rodríguez
Owner

I think it is pretty obvios that $result['aa'] should return a notice if you access something that does not exist, I don't get why would you consider that something desirable

Mark Story
Owner

The thinking was that it was the only find type to return false. find(count) clearly will return an int at all times. But find(all, list, neighbors) all return arrays even on failure.

Mark
Collaborator

@ func0der: You do not check with isset() here but with !emtpy(). isset() would only work for NULL return values.

You can also just check the result directly. So using an empty array you have the exact same behavior as false if you do:

$result = $this->Model->find('first');
if ($result) {
    $value = $result['Model']['value'];
} else {
    // no record found - do not access the array
}

If there is no result you should not try to access any keys/values in that array.

Lars

@dereuromark You used the wrong name :P
I meant to use "isset($result['aa'])" to check for an index in an array to be set. Isset() won't work on an empty array, that's true.
I tested your code before posting my initial comment, and recognized that, too. It was one of my main concernes about this change. But you are right, there is no real difference.

@markstory Ahh. Okay. Thank you for that information. I thought find('all') returns also false, but I was wrong there as it seems. Considering that you are trying to unify all the finds shouldn't read() be changed to this behavior, too? The return comment on read() is wrong at the moment: " * @return array Array of database fields, or false if not found". It does return false only if the id is NULL or FALSE. If there were no entries in the database for that special id it woud return an empty array, because it is just a wrapper method for find('first') with primary key as condition.

@lorenzo You are right, PHP should return something. But if the content of the variable is actually FALSE and not an array it would not trigger any notice messages if the requested index is not present. This saves just some lines of code here and there and is not really best or even good practice. I just mentioned it, because maybe some applications are relying on that fact. My core question was: Why the change. Which markstory answered already ;)

Mark Story
Owner

read() is a warty method on Model. It will probably be removed in 3.x as its inconsistent and bad.

Ber Clausen

@func0der to late here but the rationale was #917

Lars

Yeah. You are right. I used it so much before is recognized it kills my whole application because model states are saved in classregistry.

Whatever. Thank all of you for your explanation. :)

Please sign in to comment.
Something went wrong with that request. Please try again.