a tiny mvc framework for php using php-activerecord
at v1 428 lines 12 kB view raw
1<?php 2include 'helpers/config.php'; 3use ActiveRecord\DateTime; 4 5class DirtyAuthor extends ActiveRecord\Model 6{ 7 static $table = 'authors'; 8 static $before_save = 'before_save'; 9 10 public function before_save() 11 { 12 $this->name = 'i saved'; 13 } 14}; 15 16class AuthorWithoutSequence extends ActiveRecord\Model 17{ 18 static $table = 'authors'; 19 static $sequence = 'invalid_seq'; 20} 21 22class AuthorExplicitSequence extends ActiveRecord\Model 23{ 24 static $sequence = 'blah_seq'; 25} 26 27class ActiveRecordWriteTest extends DatabaseTest 28{ 29 private function make_new_book_and($save=true) 30 { 31 $book = new Book(); 32 $book->name = 'rivers cuomo'; 33 $book->special = 1; 34 35 if ($save) 36 $book->save(); 37 38 return $book; 39 } 40 41 public function test_save() 42 { 43 $venue = new Venue(array('name' => 'Tito')); 44 $venue->save(); 45 } 46 47 public function test_insert() 48 { 49 $author = new Author(array('name' => 'Blah Blah')); 50 $author->save(); 51 $this->assert_not_null(Author::find($author->id)); 52 } 53 54 /** 55 * @expectedException ActiveRecord\DatabaseException 56 */ 57 public function test_insert_with_no_sequence_defined() 58 { 59 if (!$this->conn->supports_sequences()) 60 throw new ActiveRecord\DatabaseException(''); 61 62 AuthorWithoutSequence::create(array('name' => 'Bob!')); 63 } 64 65 public function test_insert_should_quote_keys() 66 { 67 $author = new Author(array('name' => 'Blah Blah')); 68 $author->save(); 69 $this->assert_true(strpos($author->connection()->last_query,$author->connection()->quote_name('updated_at')) !== false); 70 } 71 72 public function test_save_auto_increment_id() 73 { 74 $venue = new Venue(array('name' => 'Bob')); 75 $venue->save(); 76 $this->assert_true($venue->id > 0); 77 } 78 79 public function test_sequence_was_set() 80 { 81 if ($this->conn->supports_sequences()) 82 $this->assert_equals($this->conn->get_sequence_name('authors','author_id'),Author::table()->sequence); 83 else 84 $this->assert_null(Author::table()->sequence); 85 } 86 87 public function test_sequence_was_explicitly_set() 88 { 89 if ($this->conn->supports_sequences()) 90 $this->assert_equals(AuthorExplicitSequence::$sequence,AuthorExplicitSequence::table()->sequence); 91 else 92 $this->assert_null(Author::table()->sequence); 93 } 94 95 public function test_delete() 96 { 97 $author = Author::find(1); 98 $author->delete(); 99 100 $this->assert_false(Author::exists(1)); 101 } 102 103 public function test_delete_by_find_all() 104 { 105 $books = Book::all(); 106 107 foreach ($books as $model) 108 $model->delete(); 109 110 $res = Book::all(); 111 $this->assert_equals(0,count($res)); 112 } 113 114 public function test_update() 115 { 116 $book = Book::find(1); 117 $new_name = 'new name'; 118 $book->name = $new_name; 119 $book->save(); 120 121 $this->assert_same($new_name, $book->name); 122 $this->assert_same($new_name, $book->name, Book::find(1)->name); 123 } 124 125 public function test_update_should_quote_keys() 126 { 127 $book = Book::find(1); 128 $book->name = 'new name'; 129 $book->save(); 130 $this->assert_true(strpos($book->connection()->last_query,$book->connection()->quote_name('name')) !== false); 131 } 132 133 public function test_update_attributes() 134 { 135 $book = Book::find(1); 136 $new_name = 'How to lose friends and alienate people'; // jax i'm worried about you 137 $attrs = array('name' => $new_name); 138 $book->update_attributes($attrs); 139 140 $this->assert_same($new_name, $book->name); 141 $this->assert_same($new_name, $book->name, Book::find(1)->name); 142 } 143 144 /** 145 * @expectedException ActiveRecord\UndefinedPropertyException 146 */ 147 public function test_update_attributes_undefined_property() 148 { 149 $book = Book::find(1); 150 $book->update_attributes(array('name' => 'new name', 'invalid_attribute' => true , 'another_invalid_attribute' => 'blah')); 151 } 152 153 public function test_update_attribute() 154 { 155 $book = Book::find(1); 156 $new_name = 'some stupid self-help book'; 157 $book->update_attribute('name', $new_name); 158 159 $this->assert_same($new_name, $book->name); 160 $this->assert_same($new_name, $book->name, Book::find(1)->name); 161 } 162 163 /** 164 * @expectedException ActiveRecord\UndefinedPropertyException 165 */ 166 public function test_update_attribute_undefined_property() 167 { 168 $book = Book::find(1); 169 $book->update_attribute('invalid_attribute', true); 170 } 171 172 public function test_save_null_value() 173 { 174 $book = Book::first(); 175 $book->name = null; 176 $book->save(); 177 $this->assert_same(null,Book::find($book->id)->name); 178 } 179 180 public function test_save_blank_value() 181 { 182 // oracle doesn't do blanks. probably an option to enable? 183 if ($this->conn instanceof ActiveRecord\OciAdapter) 184 return; 185 186 $book = Book::find(1); 187 $book->name = ''; 188 $book->save(); 189 $this->assert_same('',Book::find(1)->name); 190 } 191 192 public function test_dirty_attributes() 193 { 194 $book = $this->make_new_book_and(false); 195 $this->assert_equals(array('name','special'),array_keys($book->dirty_attributes())); 196 } 197 198 public function test_dirty_attributes_cleared_after_saving() 199 { 200 $book = $this->make_new_book_and(); 201 $this->assert_true(strpos($book->table()->last_sql,'name') !== false); 202 $this->assert_true(strpos($book->table()->last_sql,'special') !== false); 203 $this->assert_equals(null,$book->dirty_attributes()); 204 } 205 206 public function test_dirty_attributes_cleared_after_inserting() 207 { 208 $book = $this->make_new_book_and(); 209 $this->assert_equals(null,$book->dirty_attributes()); 210 } 211 212 public function test_no_dirty_attributes_but_still_insert_record() 213 { 214 $book = new Book; 215 $this->assert_equals(null,$book->dirty_attributes()); 216 $book->save(); 217 $this->assert_equals(null,$book->dirty_attributes()); 218 $this->assert_not_null($book->id); 219 } 220 221 public function test_dirty_attributes_cleared_after_updating() 222 { 223 $book = Book::first(); 224 $book->name = 'rivers cuomo'; 225 $book->save(); 226 $this->assert_equals(null,$book->dirty_attributes()); 227 } 228 229 public function test_dirty_attributes_after_reloading() 230 { 231 $book = Book::first(); 232 $book->name = 'rivers cuomo'; 233 $book->reload(); 234 $this->assert_equals(null,$book->dirty_attributes()); 235 } 236 237 public function test_dirty_attributes_with_mass_assignment() 238 { 239 $book = Book::first(); 240 $book->set_attributes(array('name' => 'rivers cuomo')); 241 $this->assert_equals(array('name'), array_keys($book->dirty_attributes())); 242 } 243 244 public function test_timestamps_set_before_save() 245 { 246 $author = new Author; 247 $author->save(); 248 $this->assert_not_null($author->created_at, $author->updated_at); 249 250 $author->reload(); 251 $this->assert_not_null($author->created_at, $author->updated_at); 252 } 253 254 public function test_timestamps_updated_at_only_set_before_update() 255 { 256 $author = new Author(); 257 $author->save(); 258 $created_at = $author->created_at; 259 $updated_at = $author->updated_at; 260 sleep(1); 261 262 $author->name = 'test'; 263 $author->save(); 264 265 $this->assert_not_null($author->updated_at); 266 $this->assert_same($created_at, $author->created_at); 267 $this->assert_not_equals($updated_at, $author->updated_at); 268 } 269 270 public function test_create() 271 { 272 $author = Author::create(array('name' => 'Blah Blah')); 273 $this->assert_not_null(Author::find($author->id)); 274 } 275 276 public function test_create_should_set_created_at() 277 { 278 $author = Author::create(array('name' => 'Blah Blah')); 279 $this->assert_not_null($author->created_at); 280 } 281 282 /** 283 * @expectedException ActiveRecord\ActiveRecordException 284 */ 285 public function test_update_with_no_primary_key_defined() 286 { 287 Author::table()->pk = array(); 288 $author = Author::first(); 289 $author->name = 'blahhhhhhhhhh'; 290 $author->save(); 291 } 292 293 /** 294 * @expectedException ActiveRecord\ActiveRecordException 295 */ 296 public function test_delete_with_no_primary_key_defined() 297 { 298 Author::table()->pk = array(); 299 $author = author::first(); 300 $author->delete(); 301 } 302 303 public function test_inserting_with_explicit_pk() 304 { 305 $author = Author::create(array('author_id' => 9999, 'name' => 'blah')); 306 $this->assert_equals(9999,$author->author_id); 307 } 308 309 /** 310 * @expectedException ActiveRecord\ReadOnlyException 311 */ 312 public function test_readonly() 313 { 314 $author = Author::first(array('readonly' => true)); 315 $author->save(); 316 } 317 318 public function test_modified_attributes_in_before_handlers_get_saved() 319 { 320 $author = DirtyAuthor::first(); 321 $author->encrypted_password = 'coco'; 322 $author->save(); 323 $this->assert_equals('i saved',DirtyAuthor::find($author->id)->name); 324 } 325 326 public function test_is_dirty() 327 { 328 $author = Author::first(); 329 $this->assert_equals(false,$author->is_dirty()); 330 331 $author->name = 'coco'; 332 $this->assert_equals(true,$author->is_dirty()); 333 } 334 335 public function test_set_date_flags_dirty() 336 { 337 $author = Author::create(array('some_date' => new DateTime())); 338 $author = Author::find($author->id); 339 $author->some_date->setDate(2010,1,1); 340 $this->assert_has_keys('some_date', $author->dirty_attributes()); 341 } 342 343 public function test_set_date_flags_dirty_with_php_datetime() 344 { 345 $author = Author::create(array('some_date' => new \DateTime())); 346 $author = Author::find($author->id); 347 $author->some_date->setDate(2010,1,1); 348 $this->assert_has_keys('some_date', $author->dirty_attributes()); 349 } 350 351 public function test_delete_all_with_conditions_as_string() 352 { 353 $num_affected = Author::delete_all(array('conditions' => 'parent_author_id = 2')); 354 $this->assert_equals(2, $num_affected); 355 } 356 357 public function test_delete_all_with_conditions_as_hash() 358 { 359 $num_affected = Author::delete_all(array('conditions' => array('parent_author_id' => 2))); 360 $this->assert_equals(2, $num_affected); 361 } 362 363 public function test_delete_all_with_conditions_as_array() 364 { 365 $num_affected = Author::delete_all(array('conditions' => array('parent_author_id = ?', 2))); 366 $this->assert_equals(2, $num_affected); 367 } 368 369 public function test_delete_all_with_limit_and_order() 370 { 371 if (!$this->conn->accepts_limit_and_order_for_update_and_delete()) 372 $this->mark_test_skipped('Only MySQL & Sqlite accept limit/order with UPDATE clause'); 373 374 $num_affected = Author::delete_all(array('conditions' => array('parent_author_id = ?', 2), 'limit' => 1, 'order' => 'name asc')); 375 $this->assert_equals(1, $num_affected); 376 $this->assert_true(strpos(Author::table()->last_sql, 'ORDER BY name asc LIMIT 1') !== false); 377 } 378 379 public function test_update_all_with_set_as_string() 380 { 381 $num_affected = Author::update_all(array('set' => 'parent_author_id = 2')); 382 $this->assert_equals(2, $num_affected); 383 $this->assert_equals(4, Author::count_by_parent_author_id(2)); 384 } 385 386 public function test_update_all_with_set_as_hash() 387 { 388 $num_affected = Author::update_all(array('set' => array('parent_author_id' => 2))); 389 $this->assert_equals(2, $num_affected); 390 } 391 392 /** 393 * TODO: not implemented 394 public function test_update_all_with_set_as_array() 395 { 396 $num_affected = Author::update_all(array('set' => array('parent_author_id = ?', 2))); 397 $this->assert_equals(2, $num_affected); 398 } 399 */ 400 401 public function test_update_all_with_conditions_as_string() 402 { 403 $num_affected = Author::update_all(array('set' => 'parent_author_id = 2', 'conditions' => 'name = "Tito"')); 404 $this->assert_equals(1, $num_affected); 405 } 406 407 public function test_update_all_with_conditions_as_hash() 408 { 409 $num_affected = Author::update_all(array('set' => 'parent_author_id = 2', 'conditions' => array('name' => "Tito"))); 410 $this->assert_equals(1, $num_affected); 411 } 412 413 public function test_update_all_with_conditions_as_array() 414 { 415 $num_affected = Author::update_all(array('set' => 'parent_author_id = 2', 'conditions' => array('name = ?', "Tito"))); 416 $this->assert_equals(1, $num_affected); 417 } 418 419 public function test_update_all_with_limit_and_order() 420 { 421 if (!$this->conn->accepts_limit_and_order_for_update_and_delete()) 422 $this->mark_test_skipped('Only MySQL & Sqlite accept limit/order with UPDATE clause'); 423 424 $num_affected = Author::update_all(array('set' => 'parent_author_id = 2', 'limit' => 1, 'order' => 'name asc')); 425 $this->assert_equals(1, $num_affected); 426 $this->assert_true(strpos(Author::table()->last_sql, 'ORDER BY name asc LIMIT 1') !== false); 427 } 428};