Changeset 119
- Timestamp:
- 03/03/07 23:51:33 (2 years ago)
- Files:
-
- trunk/MAINTAINERS.txt (modified) (1 diff)
- trunk/THANKS.txt (modified) (2 diffs)
- trunk/lib/AkActiveRecord.php (modified) (36 diffs)
- trunk/lib/AkActiveRecord/AkHasAndBelongsToMany.php (modified) (1 diff)
- trunk/test/fixtures/app/installers/protected_person_installer.php (modified) (1 diff)
- trunk/test/unit/lib/AkActiveRecord.php (modified) (2 diffs)
- trunk/test/unit/lib/_AkActiveRecord_1.php (modified) (6 diffs)
- trunk/test/unit/lib/_AkActiveRecord_2.php (modified) (14 diffs)
- trunk/test/unit/lib/_AkActiveRecord_accessible_attributes.php (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/MAINTAINERS.txt
r117 r119 5 5 Niels Ganser <niels.ganser.nospam-gmail-d.ot-co.m> Core Contributor 6 6 7 Kaste <thdz DOT x gmx net> Core Contributor 8 7 9 See THANKS.txt for the complete list of people who has made Akelos possible 8 10 trunk/THANKS.txt
r117 r119 20 20 - AkActsAsTree.php unit tested new feature 2006-09-20 21 21 22 Kaste 23 24 - AkInstaller patch and new unit test. 2007-02-25 25 - AkActiveRecord::accessibleAttributes patch and new unit test. 2007-02-26 26 - AkActiveRecord refactoring and improvement. 2007-03-03 22 27 23 28 … … 33 38 - AkXhtmlValidator.php patch. 2007-02-23 34 39 35 Kaste36 37 - AkInstaller patch and new unit test. 2007-02-2538 - AkActiveRecord::accessibleAttributes patch and new unit test. 2007-02-2639 40 40 41 41 Special thanks to David Heinemeier Hansson and the Rails community for creating trunk/lib/AkActiveRecord.php
r118 r119 12 12 * @package AkelosFramework 13 13 * @subpackage AkActiveRecord 14 * @author Bermi Ferrer <bermi a.t akelos c.om> 14 * @author Bermi Ferrer <bermi a.t akelos c.om> 2004 - 2007 15 * @author Kaste 2007 15 16 * @copyright Copyright (c) 2002-2006, Akelos Media, S.L. http://www.akelos.org 16 17 * @license GNU Lesser General Public License <http://www.gnu.org/copyleft/lesser.html> … … 19 20 require_once(AK_LIB_DIR.DS.'AkActiveRecord'.DS.'AkAssociatedActiveRecord.php'); 20 21 21 if(!defined('AK_ACTIVE_RECORD_VALIDATE_TABLE_NAMES')){ 22 define('AK_ACTIVE_RECORD_VALIDATE_TABLE_NAMES', true); 23 } 24 if(!defined('AK_ACTIVE_RECORD_ENABLE_PERSISTENCE')){ 25 define('AK_ACTIVE_RECORD_ENABLE_PERSISTENCE', true); 26 } 27 if(!defined('AK_NOT_EMPTY_REGULAR_EXPRESSION')){ 28 define('AK_NOT_EMPTY_REGULAR_EXPRESSION','/.+/'); 29 } 30 if(!defined('AK_EMAIL_REGULAR_EXPRESSION')){ 31 define('AK_EMAIL_REGULAR_EXPRESSION',"/^([a-z0-9_\-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-z0-9\-]+\.)+))([a-z]{2,4}|[0-9]{1,3})(\]?)$/i"); 32 } 33 if(!defined('AK_NUMBER_REGULAR_EXPRESSION')){ 34 define('AK_NUMBER_REGULAR_EXPRESSION',"/^[0-9]+$/"); 35 } 36 if(!defined('AK_PHONE_REGULAR_EXPRESSION')){ 37 define('AK_PHONE_REGULAR_EXPRESSION',"/^([\+]?[(]?[\+]?[ ]?[0-9]{2,3}[)]?[ ]?)?[0-9 ()\-]{4,25}$/"); 38 } 39 if(!defined('AK_DATE_REGULAR_EXPRESSION')){ 40 define('AK_DATE_REGULAR_EXPRESSION',"/^(([0-9]{1,2}(\-|\/|\.| )[0-9]{1,2}(\-|\/|\.| )[0-9]{2,4})|([0-9]{2,4}(\-|\/|\.| )[0-9]{1,2}(\-|\/|\.| )[0-9]{1,2})){1}$/"); 41 } 42 if(!defined('AK_IP4_REGULAR_EXPRESSION')){ 43 define('AK_IP4_REGULAR_EXPRESSION',"/^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$/"); 44 } 45 if(!defined('AK_POST_CODE_REGULAR_EXPRESSION')){ 46 define('AK_POST_CODE_REGULAR_EXPRESSION',"/^[0-9A-Za-z -]{2,9}$/"); 47 } 22 ak_define('ACTIVE_RECORD_VALIDATE_TABLE_NAMES', true); 23 ak_define('ACTIVE_RECORD_ENABLE_PERSISTENCE', true); 24 ak_define('ACTIVE_RECORD_SKIP_SETTING_ACTIVE_RECORD_DEFAULTS', false); 25 ak_define('NOT_EMPTY_REGULAR_EXPRESSION','/.+/'); 26 ak_define('EMAIL_REGULAR_EXPRESSION',"/^([a-z0-9_\-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-z0-9\-]+\.)+))([a-z]{2,4}|[0-9]{1,3})(\]?)$/i"); 27 ak_define('NUMBER_REGULAR_EXPRESSION',"/^[0-9]+$/"); 28 ak_define('PHONE_REGULAR_EXPRESSION',"/^([\+]?[(]?[\+]?[ ]?[0-9]{2,3}[)]?[ ]?)?[0-9 ()\-]{4,25}$/"); 29 ak_define('DATE_REGULAR_EXPRESSION',"/^(([0-9]{1,2}(\-|\/|\.| )[0-9]{1,2}(\-|\/|\.| )[0-9]{2,4})|([0-9]{2,4}(\-|\/|\.| )[0-9]{1,2}(\-|\/|\.| )[0-9]{1,2})){1}$/"); 30 ak_define('IP4_REGULAR_EXPRESSION',"/^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$/"); 31 ak_define('POST_CODE_REGULAR_EXPRESSION',"/^[0-9A-Za-z -]{2,9}$/"); 48 32 49 33 Ak::compat('array_combine'); … … 185 169 var $_attributes = array(); 186 170 187 var $_protectedAt ributes = array();171 var $_protectedAttributes = array(); 188 172 var $_accessibleAttributes = array(); 189 173 … … 260 244 if(!empty($this->combined_attributes)){ 261 245 foreach ($this->combined_attributes as $combined_attribute){ 262 call_user_func_array(array(&$this,'addCombinedAttributeConfiguration'), $combined_attribute); 263 } 264 } 265 266 //$this->initiateAssociations(); 267 268 269 // new AkActiveRecord(array('username'=>'bermi','pass'=>'mypass')); Sets attributes for creating a new entry or finding a new record 246 $this->addCombinedAttributeConfiguration($combined_attribute); 247 } 248 } 249 270 250 if(isset($attributes[0]) && is_array($attributes[0]) && count($attributes) === 1){ 271 251 $attributes = $attributes[0]; … … 289 269 $this->setAttributes($attributes[1], true); 290 270 }else{ 291 $this->_newRecord = true; 292 // new AkActiveRecord('username->','bermi','pass->','mypass'); // Sets attributes for creating a new entry or finding a new record using an special sintax 293 if(isset($attributes[0]) && !is_array($attributes[0])){ 294 $this->parseAkelosArgs($attributes); 295 } 296 $attributes = $this->attributesFromColumnDefinition($attributes); 297 298 foreach ($attributes as $k=>$v){ 299 $this->setAttribute($k, $v); 300 } 301 302 $this->composeCombinedAttributes(); 303 } 304 305 if(count($attributes) === 0){ 306 $this->_newRecord = true; 271 $this->newRecord($attributes); 307 272 } 308 273 … … 319 284 320 285 /** 321 * If this macro is used, only those attributed named in it will be accessible for mass-assignment, such as new ModelName($attributes) and $this->attributes($attributes). This is the more conservative choice for mass-assignment protection. If you?d rather start from an all-open default and restrict attributes as needed, have a look at AkActiveRecord::attrProtected. 286 * If this macro is used, only those attributed named in it will be accessible 287 * for mass-assignment, such as new ModelName($attributes) and $this->attributes($attributes). 288 * This is the more conservative choice for mass-assignment protection. 289 * If you'd rather start from an all-open default and restrict attributes as needed, 290 * have a look at AkActiveRecord::setProtectedAttributes(). 322 291 */ 323 292 function setAccessibleAttributes() … … 328 297 329 298 /** 330 Attributes named in this macro are protected from mass-assignment, such as new ModelName($attributes) and $this->attributes(attributes). Their assignment will simply be ignored. Instead, you can use the direct writer methods to do assignment. This is meant to protect sensitive attributes to be overwritten by URL/form hackers. Example: 331 <code> 332 class Customer extends AkActiveRecord 333 { 334 function Customer() 335 { 336 $this->setProtectedAttributes('credit_rating'); 337 } 338 } 339 340 $Customer = new Customer('name' => 'David', 'credit_rating' => 'Excellent'); 341 $Customer->credit_rating // => null 342 $Customer->attributes(array('description' => 'Jolly fellow', 'credit_rating' => 'Superb')); 343 $Customer->credit_rating // => null 344 345 $Customer->credit_rating = 'Average' 346 $Customer->credit_rating // => 'Average' 347 </code> 348 */ 299 * Attributes named in this macro are protected from mass-assignment, such as 300 * new ModelName($attributes) and $this->attributes(attributes). Their assignment 301 * will simply be ignored. Instead, you can use the direct writer methods to do assignment. 302 * This is meant to protect sensitive attributes to be overwritten by URL/form hackers. 303 * 304 * Example: 305 * <code> 306 * class Customer extends AkActiveRecord 307 * { 308 * function Customer() 309 * { 310 * $this->setProtectedAttributes('credit_rating'); 311 * } 312 * } 313 * 314 * $Customer = new Customer('name' => 'David', 'credit_rating' => 'Excellent'); 315 * $Customer->credit_rating // => null 316 * $Customer->attributes(array('description' => 'Jolly fellow', 'credit_rating' => 'Superb')); 317 * $Customer->credit_rating // => null 318 * 319 * $Customer->credit_rating = 'Average' 320 * $Customer->credit_rating // => 'Average' 321 * </code> 322 */ 349 323 function setProtectedAttributes() 350 324 { 351 325 $args = func_get_args(); 352 $this->_protectedAt ributes = array_unique(array_merge((array)$this->_protectedAtributes, $args));326 $this->_protectedAttributes = array_unique(array_merge((array)$this->_protectedAttributes, $args)); 353 327 } 354 328 … … 363 337 364 338 /** 365 * Returns the connection currently associated with the class. This can also be used to "borrow" the connection to do database work unrelated to any of the specific Active Records. 339 * Returns the connection currently associated with the class. This can also be used to 340 * "borrow" the connection to do database work unrelated to any of the specific Active Records. 366 341 */ 367 342 function &getConnection() … … 379 354 380 355 /** 381 * Returns an array of columns objects where the primary id, all columns ending in "_id" or "_count", and columns used for single table inheritance has been removed. 356 * Returns an array of columns objects where the primary id, all columns ending in "_id" or "_count", 357 * and columns used for single table inheritance has been removed. 382 358 */ 383 359 function getContentColumns() … … 397 373 398 374 /** 399 * Creates an object, instantly saves it as a record (if the validation permits it), and returns it. If the save fail under validations, the unsaved object is still returned. 375 * Creates an object, instantly saves it as a record (if the validation permits it), and returns it. 376 * If the save fail under validations, the unsaved object is still returned. 400 377 */ 401 378 function &create($attributes = null) … … 408 385 $attributes = func_get_args(); 409 386 } 410 $this->parseAkelosArgs($attributes);411 387 $model = $this->getModelName(); 412 388 … … 419 395 420 396 /** 421 * Returns the number of records that meet the 'conditions'. Zero is returned if no records match. Example: 397 * Returns the number of records that meet the 'conditions'. Zero is returned if no records match. 398 * 399 * Example: 422 400 * $Product->count("sales > 1"); 423 401 */ … … 438 416 /** 439 417 * Returns the result of an SQL statement that should only include a COUNT(*) in the SELECT part. 418 * 440 419 * $Product->countBySql("SELECT COUNT(*) FROM sales s, customers c WHERE s.customer_id = c.id"); 441 420 */ … … 457 436 458 437 /** 459 * Increments the specified counter by one. So $DiscussionBoard->incrementCounter("post_count", $discussion_board_id); would increment the "post_count" counter on the board responding to $discussion_board_id. This is used for caching aggregate values, so that they doesn't need to be computed every time. Especially important for looping over a collection where each element require a number of aggregate values. Like the $DiscussionBoard that needs to list both the number of posts and comments. 438 * Increments the specified counter by one. So $DiscussionBoard->incrementCounter("post_count", 439 * $discussion_board_id); would increment the "post_count" counter on the board responding to 440 * $discussion_board_id. This is used for caching aggregate values, so that they doesn't need to 441 * be computed every time. Especially important for looping over a collection where each element 442 * require a number of aggregate values. Like the $DiscussionBoard that needs to list both the number of posts and comments. 460 443 */ 461 444 function incrementCounter($counter_name, $id, $difference = 1) … … 484 467 485 468 /** 486 * Finds the record from the passed id, instantly saves it with the passed attributes (if the validation permits it), and returns it. If the save fail under validations, the unsaved object is still returned. 469 * Finds the record from the passed id, instantly saves it with the passed attributes (if the validation permits it), 470 * and returns it. If the save fail under validations, the unsaved object is still returned. 487 471 */ 488 472 function update($id, $attributes) … … 493 477 if(is_array($id)){ 494 478 $results = array(); 495 foreach ($id as $ single_id){496 $results[] = $this->update($single_id, $attributes);479 foreach ($id as $idx=>$single_id){ 480 $results[] = $this->update($single_id, isset($attributes[$idx]) ? $attributes[$idx] : $attributes); 497 481 } 498 482 return $results; 499 483 }else{ 500 $object = $this->find($id);501 $object->updateAttributes($attributes , $object);484 $object =& $this->find($id); 485 $object->updateAttributes($attributes); 502 486 return $object; 503 487 } … … 505 489 506 490 /** 507 * Updates a single attribute and saves the record. This is especially useful for boolean flags on existing records. Note: Make sure that updates made with this method doesn't get subjected to validation checks. Hence, attributes can be updated even if the full object isn't valid. 491 * Updates a single attribute and saves the record. This is especially useful for boolean flags on existing records. 492 * Note: Make sure that updates made with this method doesn't get subjected to validation checks. 493 * Hence, attributes can be updated even if the full object isn't valid. 508 494 */ 509 495 function updateAttribute($name, $value) … … 515 501 516 502 /** 517 * Updates all the attributes in from the passed array and saves the record. If the object is invalid, the saving will fail and false will be returned. 503 * Updates all the attributes in from the passed array and saves the record. If the object is 504 * invalid, the saving will fail and false will be returned. 518 505 */ 519 506 function updateAttributes($attributes, $object = null) 520 507 { 521 foreach ($attributes as $attribute=>$value){ 522 isset($object) ? $object->setAttribute($attribute, $value) : $this->setAttribute($attribute, $value); 523 } 508 isset($object) ? $object->setAttributes($attributes) : $this->setAttributes($attributes); 524 509 525 510 return isset($object) ? $object->save() : $this->save(); … … 530 515 531 516 /** 532 * Updates all records with the SET-part of an SQL update statement in updates and returns an integer with the number of rows updates. A subset of the records can be selected by specifying conditions. Example: 517 * Updates all records with the SET-part of an SQL update statement in updates and returns an 518 * integer with the number of rows updates. A subset of the records can be selected by specifying conditions. Example: 533 519 * <code>$Billing->updateAll("category = 'authorized', approved = 1", "author = 'David'");</code> 520 * 521 * Important note: Condifitons are not sanitized yet so beware of accepting 522 * variable conditions when using this function 534 523 */ 535 524 function updateAll($updates, $conditions = null) … … 551 540 552 541 /** 553 * Deletes the record with the given id without instantiating an object first. If an array of ids is provided, all of them are deleted. 542 * Deletes the record with the given id without instantiating an object first. If an array of 543 * ids is provided, all of them are deleted. 554 544 */ 555 545 function delete($id) … … 590 580 591 581 /** 592 * Deletes all the records that matches the condition without instantiating the objects first (and hence not calling the destroy method). Example: 582 * Deletes all the records that matches the condition without instantiating the objects first 583 * (and hence not calling the destroy method). Example: 584 * 593 585 * <code>$Post->destroyAll("person_id = 5 AND (category = 'Something' OR category = 'Else')");</code> 586 * 587 * Important note: Condifitons are not sanitized yet so beware of accepting 588 * variable conditions when using this function 594 589 */ 595 590 function deleteAll($conditions = null) … … 612 607 613 608 /** 614 * Destroys the record with the given id by instantiating the object and calling destroy (all the callbacks are the triggered). If an array of ids is provided, all of them are destroyed. 615 * Deletes the record in the database and freezes this instance to reflect that no changes should be made (since they can't be persisted). 609 * Destroys the record with the given id by instantiating the object and calling destroy 610 * (all the callbacks are the triggered). If an array of ids is provided, all of them are destroyed. 611 * Deletes the record in the database and freezes this instance to reflect that no changes should be 612 * made (since they can't be persisted). 616 613 */ 617 614 function destroy($id = null) … … 644 641 if($this->beforeDestroy()){ 645 642 $this->notifyObservers('beforeDestroy'); 646 /** 647 * @todo sanitize and quote id 648 */ 643 649 644 $sql = 'DELETE FROM '.$this->getTableName().' WHERE '.$this->getPrimaryKey().' = '.$this->_db->qstr($this->getId()); 650 645 … … 684 679 685 680 /** 686 * Destroys the objects for all the records that matches the condition by instantiating each object and calling the destroy method. Example: 687 * $Person->destroyAll("last_login < '2004-04-04'"); 681 * Destroys the objects for all the records that matches the condition by instantiating 682 * each object and calling the destroy method. 683 * 684 * Example: 685 * 686 * $Person->destroyAll("last_login < '2004-04-04'"); 688 687 */ 689 688 function destroyAll($conditions) … … 708 707 709 708 /** 710 * Establishes the connection to the database. Accepts an array as input where the 'adapter' key must be specified with the name of a database adapter (in lower-case) example for regular databases (MySQL, Postgresql, etc): 711 712 $AkActiveRecord->establishConnection( 713 array( 714 'adapter' => "mysql", 715 'host' => "localhost", 716 'username' => "myuser", 717 'password' => "mypass", 718 'database' => "somedatabase" 719 ) 720 ) 721 722 Example for SQLite database: 723 724 $AkActiveRecord->establishConnection( 725 array( 726 'adapter' => "sqlite", 727 'dbfile' => "path/to/dbfile" 728 ) 729 ) 709 * Establishes the connection to the database. Accepts an array as input where the 'adapter' 710 * key must be specified with the name of a database adapter (in lower-case) example for regular 711 * databases (MySQL, Postgresql, etc): 712 * 713 * $AkActiveRecord->establishConnection( 714 * array( 715 * 'adapter' => "mysql", 716 * 'host' => "localhost", 717 * 'username' => "myuser", 718 * 'password' => "mypass", 719 * 'database' => "somedatabase" 720 * )); 721 * 722 * Example for SQLite database: 723 * 724 * $AkActiveRecord->establishConnection( 725 * array( 726 * 'adapter' => "sqlite", 727 * 'dbfile' => "path/to/dbfile" 728 * ) 729 * ) 730 730 */ 731 731 function &establishConnection($spec = null) … … 774 774 775 775 /** 776 Find operates with three different retrieval approaches: 777 778 * Find by id: This can either be a specific id find(1), a list of ids find(1, 5, 6), or an array of ids find(array(5, 6, 10)). If no record can be found for all of the listed ids, then RecordNotFound will be raised. 779 * Find first: This will return the first record matched by the options used. These options can either be specific conditions or merely an order. If no record can matched, false is returned. 780 * Find all: This will return all the records matched by the options used. If no records are found, an empty array is returned. 781 782 All approaches accepts an $option array as their last parameter. The options are: 783 776 * Find operates with three different retrieval approaches: 777 * * Find by id: This can either be a specific id find(1), a list of ids find(1, 5, 6), 778 * or an array of ids find(array(5, 6, 10)). If no record can be found for all of the listed ids, 779 * then RecordNotFound will be raised. 780 * * Find first: This will return the first record matched by the options used. These options 781 * can either be specific conditions or merely an order. 782 * If no record can matched, false is returned. 783 * * Find all: This will return all the records matched by the options used. If no records are found, an empty array is returned. 784 * 785 * All approaches accepts an $option array as their last parameter. The options are: 786 * 784 787 * 'conditions' => An SQL fragment like "administrator = 1" or array("user_name = ?" => $username). See conditions in the intro. 785 788 * 'order' => An SQL fragment like "created_at DESC, name". … … 787 790 * 'offset' => An integer determining the offset from where the rows should be fetched. So at 5, it would skip the first 4 rows. 788 791 * 'joins' => An SQL fragment for additional joins like "LEFT JOIN comments ON comments.post_id = $id". (Rarely needed). 789 * 'include' => Names associations that should be loaded alongside using LEFT OUTER JOINs. The symbols named refer to already defined associations. See eager loading under Associations. 790 792 * 'include' => Names associations that should be loaded alongside using LEFT OUTER JOINs. The symbols 793 * named refer to already defined associations. See eager loading under Associations. 794 * 791 795 Examples for find by id: 792 796 … … 1548 1552 /** 1549 1553 * New objects can be instantiated as either empty (pass no construction parameter) or pre-set with attributes but not yet saved 1550 * (pass a hashwith key names matching the associated table column names).1554 * (pass an array with key names matching the associated table column names). 1551 1555 * In both instances, valid attribute keys are determined by the column names of the associated table ? hence you can't 1552 1556 * have attributes that aren't part of the table columns. … … 1555 1559 { 1556 1560 $this->_newRecord = true; 1561 1562 if(AK_ACTIVE_RECORD_SKIP_SETTING_ACTIVE_RECORD_DEFAULTS && empty($attributes)){ 1563 return; 1564 } 1565 1557 1566 if(isset($attributes) && !is_array($attributes)){ 1558 1567 $attributes = func_get_args(); 1559 $this->parseAkelosArgs($attributes); 1560 } 1561 $attributes = $this->attributesFromColumnDefinition($attributes); 1562 1563 foreach ($attributes as $k=>$v){ 1564 $this->setAttribute($k, $v); 1565 } 1566 $this->composeCombinedAttributes(); 1568 } 1569 $this->setAttributes($this->attributesFromColumnDefinition(),true); 1570 $this->setAttributes($attributes); 1567 1571 } 1568 1572 … … 1705 1709 1706 1710 /** 1707 * Allows you to set all the attributes at once by passing in an array with keys matching the attribute names (which again matches the column names). Sensitive attributes can be protected from this form of mass-assignment by using the $this->setProtectedAttributes method. Or you can alternatively specify which attributes can be accessed in with the $this->setAccessibleAttributes method. Then all the attributes not included in that won?t be allowed to be mass-assigned. 1711 * Allows you to set all the attributes at once by passing in an array with 1712 * keys matching the attribute names (which again matches the column names). 1713 * Sensitive attributes can be protected from this form of mass-assignment by 1714 * using the $this->setProtectedAttributes method. Or you can alternatively 1715 * specify which attributes can be accessed in with the $this->setAccessibleAttributes method. 1716 * Then all the attributes not included in that won?t be allowed to be mass-assigned. 1708 1717 */ 1709 1718 function setAttributes($attributes, $override_attribute_protection = false) … … 1728 1737 } 1729 1738 } 1730 }elseif (!empty($this->_protectedAt ributes) && is_array($this->_protectedAtributes) && is_array($attributes)){1739 }elseif (!empty($this->_protectedAttributes) && is_array($this->_protectedAttributes) && is_array($attributes)){ 1731 1740 foreach (array_keys($attributes) as $k){ 1732 if(in_array($k,$this->_protectedAt ributes)){1741 if(in_array($k,$this->_protectedAttributes)){ 1733 1742 unset($attributes[$k]); 1734 1743 } … … 1834 1843 $attribute = array_shift($args); 1835 1844 $this->_combinedAttributes[$attribute] = $args; 1836 $this->composeCombinedAttribute s();1845 $this->composeCombinedAttribute($attribute); 1837 1846 } 1838 1847 } … … 2203 2212 } 2204 2213 2205 2206 /** 2207 Quote strings appropriately for SQL statements. 2208 that a new instance, or one populated from a passed-in array, still has all the attributes 2209 that instances loaded from the database would. 2210 */ 2211 function attributesFromColumnDefinition($attributes) 2214 /** 2215 * unused function; misleading named attributesFromColumnDefinition 2216 */ 2217 function filterForeignAndProtectedAttributes($attributes) 2212 2218 { 2213 2219 $filtered_attributes = array(); 2214 2220 if(is_array($attributes)){ 2215 2221 foreach ($attributes as $k=>$v){ 2216 if($this->hasAttribute($k) && !in_array($k, $this->_protectedAt ributes)){2222 if($this->hasAttribute($k) && !in_array($k, $this->_protectedAttributes)){ 2217 2223 $filtered_attributes[$k] = $v; 2218 } 2224 } 2219 2225 } 2220 2226 } 2221 2227 return $filtered_attributes; 2222 2228 } 2223 2229 2230 /** 2231 * Initializes the attributes array with keys matching the columns from the linked table and 2232 * the values matching the corresponding default value of that column, so 2233 * that a new instance, or one populated from a passed-in Hash, still has all the attributes 2234 * that instances loaded from the database would. 2235 */ 2236 function attributesFromColumnDefinition() 2237 { 2238 $attributes = array(); 2239 $availableColumns = $this->getColumns(); 2240 foreach ($availableColumns as $column_name=>$column_settings){ 2241 if (!isset($column_settings['primaryKey']) && isset($column_settings['hasDefault'])) { 2242 $attributes[$column_name] = $column_settings['defaultValue']; 2243 } else { 2244 $attributes[$column_name] = null; 2245 } 2246 } 2247 return $attributes; 2248 } 2224 2249 2225 2250 /** … … 2337 2362 $this->initiateColumnsToNull(); 2338 2363 } 2339 return $this->_columnsSettings;2364 return isset($this->_columnsSettings) ? $this->_columnsSettings : array(); 2340 2365 } 2341 2366 … … 2355 2380 $column_objects = $this->_databaseTableInternals($this->getTableName()); 2356 2381 2357 if(!is _array($column_objects)){2382 if(!isset($this->_avoidTableNameValidation) && !is_array($column_objects)){ 2358 2383 trigger_error(Ak::t('Ooops! Could not fetch details for the table %table_name.', array('%table_name'=>$this->getTableName())), E_USER_ERROR); 2359 2384 return false; 2360 }else {2385 }elseif(is_array($column_objects)){ 2361 2386 foreach ($column_objects as $column_object){ 2362 2387 $this->setColumnSettings($column_object->name, $column_object); 2363 2388 } 2364 2389 } 2365 $_SESSION['__activeRecordColumnsSettingsCache'][$model_name.'_column_settings'] = $this->_columnsSettings; 2390 if(!empty($this->_columnsSettings)){ 2391 $_SESSION['__activeRecordColumnsSettingsCache'][$model_name.'_column_settings'] = $this->_columnsSettings; 2392 } 2366 2393 }else{ 2367 2394 $this->_columnsSettings = $_SESSION['__activeRecordColumnsSettingsCache'][$model_name.'_column_settings']; 2368 2395 } 2369 2396 2370 return $this->_columnsSettings;2397 return isset($this->_columnsSettings) ? $this->_columnsSettings : array(); 2371 2398 } 2372 2399 … … 2553 2580 function initiateColumnsToNull() 2554 2581 { 2555 array_map(array(&$this,'initiateAttributeToNull'),array_keys( $this->_columnsSettings));2582 array_map(array(&$this,'initiateAttributeToNull'),array_keys(isset($this->_columnsSettings) ? $this->_columnsSettings : array())); 2556 2583 } 2557 2584 trunk/lib/AkActiveRecord/AkHasAndBelongsToMany.php
r80 r119 251 251 $class_code = 252 252 "class {$options['join_class_name']} extends {$options['join_class_extends']} { 253 var \$_avoidTableNameValidation = true; 253 254 function {$options['join_class_name']}() 254 255 { trunk/test/fixtures/app/installers/protected_person_installer.php
r102 r119 10 10 birthday datetime, 11 11 is_active boolean not null default 1, 12 credit_points int default 1000, 12 13 created_by int default null, 13 14 created_at, trunk/test/unit/lib/AkActiveRecord.php
r118 r119 11 11 define('ALL_TESTS_RUNNER', false); 12 12 @session_start(); 13 }14 15 if(!ALL_TESTS_RUNNER){16 foreach (Ak::dir(AK_LIB_TESTS_DIRECTORY.DS.'AkActiveRecord') as $active_record_test){17 $test->addTestFile(AK_LIB_TESTS_DIRECTORY.DS.'AkActiveRecord'.DS.$active_record_test);18 }19 13 } 20 14 … … 34 28 } 35 29 30 // Acts as, Validators, Associations and Observer tests 31 if(!ALL_TESTS_RUNNER){ 32 foreach (Ak::dir(AK_LIB_TESTS_DIRECTORY.DS.'AkActiveRecord') as $active_record_test){ 33 $test->addTestFile(AK_LIB_TESTS_DIRECTORY.DS.'AkActiveRecord'.DS.$active_record_test); 34 } 35 } 36 36 37 if(!ALL_TESTS_RUNNER){ 37 38 if (TextReporter::inCli()) { trunk/test/unit/lib/_AkActiveRecord_1.php
r36 r119 86 86 //var $_inheritanceColumn = "ak_test_user_id"; 87 87 function AkTestMember(){ 88 $this->setTableName("ak_test_members"); 88 89 $this->init(@(array)func_get_args()); 89 $this->setTableName("ak_test_members");90 90 } 91 91 } ?>'; … … 277 277 278 278 $this->_createNewTestingModel('AkTestUnavailableDatabase'); 279 $AkTestUnavailableDatabase = new AkTestUnavailableDatabase();280 $this->assertEqual($AkTestUnavailableDatabase->getModelName(), 'AkTestUnavailableDatabase');281 define('AK_ACTIVE_RECORD_VALIDATE_TABLE_NAMES', true);282 $this->assertErrorPattern('/AK_ACTIVE_RECORD_VALIDATE_TABLE_NAMES/',$AkTestUnavailableDatabase->getTableName());279 //$AkTestUnavailableDatabase = new AkTestUnavailableDatabase(); 280 //$this->assertEqual($AkTestUnavailableDatabase->getModelName(), 'AkTestUnavailableDatabase'); 281 ak_define('AK_ACTIVE_RECORD_VALIDATE_TABLE_NAMES', true); 282 //$this->assertErrorPattern('/Ooops! Could not fetch details for the table ak_test_unavailable_database./',$AkTestUnavailableDatabase->getTableName()); 283 283 } 284 284 … … 288 288 $input = array('first_name'=>'Bermi','last_name'=>'Ferrer Martinez','not_valid'=>'Invalid value','id'=>123); 289 289 $expected = array('first_name'=>'Bermi','last_name'=>'Ferrer Martinez','id'=>123); 290 $got = $User-> attributesFromColumnDefinition($input);290 $got = $User->filterForeignAndProtectedAttributes($input); 291 291 $this->assertEqual($got,$expected); 292 292 293 293 $User->setProtectedAttributes('last_name'); 294 294 $expected = array('first_name'=>'Bermi','id'=>123); 295 $got = $User-> attributesFromColumnDefinition($input);295 $got = $User->filterForeignAndProtectedAttributes($input); 296 296 $this->assertEqual($got,$expected); 297 297 … … 311 311 } 312 312 313 function Test_of_ set_and_getModelName()313 function Test_of_getModelName() 314 314 { 315 315 $AkTestUser = new AkTestUser(); … … 318 318 $AkTestField = new AkTestField(); 319 319 $this->assertEqual($AkTestField->getModelName(), 'AkTestField'); 320 321 if(AK_PHP5){322 $AkInvalidModel = new AkActiveRecord();323 $this->assertEqual($AkInvalidModel->getModelName(), 'AkActiveRecord');324 }else{325 $AkInvalidModel = new AkActiveRecord();326 $AkInvalidModel->setModelName('CustomModelName');327 $this->assertEqual($AkInvalidModel->getModelName(), 'CustomModelName');328 }329 330 320 } 331 321 … … 829 819 $User->setProtectedAttributes('first_name','last_name','name','country','email'); 830 820 $expected = array('first_name', 'last_name', 'name', 'country', 'email'); 831 $this->assertEqual($expected, $User->_protectedAt ributes);821 $this->assertEqual($expected, $User->_protectedAttributes); 832 822 } 833 823 trunk/test/unit/lib/_AkActiveRecord_2.php
r2 r119 20 20 $User->newRecord('last_name->','Ferrer','date->','1978-06-16','expires_on->','2120-06-16'); 21 21 $User->set('first_name','Bermi'); 22 $User->set('last_name',$User->get('last_name').' Mart ínez');23 $this->assertEqual($User->getAttributes(), array('id'=>null,'user_name'=>null,'first_name'=>'Bermi','last_name'=>'Ferrer Mart ínez','email'=>null,'country'=>null,'password'=>'*********','created_at'=>null,'updated_at'=>null,'expires_on'=>'2120-06-16'));22 $User->set('last_name',$User->get('last_name').' Mart�nez'); 23 $this->assertEqual($User->getAttributes(), array('id'=>null,'user_name'=>null,'first_name'=>'Bermi','last_name'=>'Ferrer Mart�nez','email'=>null,'country'=>null,'password'=>'*********','created_at'=>null,'updated_at'=>null,'expires_on'=>'2120-06-16')); 24 24 $this->assertTrue($User->isNewRecord()); 25 25 … … 88 88 function Test_of_find() 89 89 { 90 $User = new AkTestUser('first_name=>','Bermi','last_name->','Ferrer Mart ínez','user_name->','bermi','email->','bermi@example.com');90 $User = new AkTestUser('first_name=>','Bermi','last_name->','Ferrer Mart�nez','user_name->','bermi','email->','bermi@example.com'); 91 91 $User->_create(); 92 92 93 $User = new AkTestUser('first_name=>','Hilario','last_name->','Herv ás Añó','user_name->','hilario','email->','hilario@example.com');93 $User = new AkTestUser('first_name=>','Hilario','last_name->','Herv�s A��','user_name->','hilario','email->','hilario@example.com'); 94 94 $User->_create(); 95 95 96 96 $Users = new AkTestUser(); 97 97 $User = $Users->find(3); 98 $this->assertTrue($User->first_name=='Bermi' && $User->last_name == 'Ferrer Mart ínez' && $User->user_name == 'bermi' && $User->email == 'bermi@example.com');98 $this->assertTrue($User->first_name=='Bermi' && $User->last_name == 'Ferrer Mart�nez' && $User->user_name == 'bermi' && $User->email == 'bermi@example.com'); 99 99 100 100 $Users = new AkTestUser(); … … 102 102 103 103 foreach ($FoundUsers as $User){ 104 $expected1 = ($User->first_name=='Hilario' && $User->last_name == 'Herv ás Añó' && $User->user_name == 'hilario' && $User->email == 'hilario@example.com');105 $expected2 = ($User->first_name=='Bermi' && $User->last_name == 'Ferrer Mart ínez' && $User->user_name == 'bermi' && $User->email == 'bermi@example.com');104 $expected1 = ($User->first_name=='Hilario' && $User->last_name == 'Herv�s A��' && $User->user_name == 'hilario' && $User->email == 'hilario@example.com'); 105 $expected2 = ($User->first_name=='Bermi' && $User->last_name == 'Ferrer Mart�nez' && $User->user_name == 'bermi' && $User->email == 'bermi@example.com'); 106 106 $this->assertTrue($expected1 || $expected2); 107 107 } … … 116 116 $GotUser = $Users->find(array(3)); 117 117 $User = $GotUser[0]; 118 $this->assertTrue($User->first_name=='Bermi' && $User->last_name == 'Ferrer Mart ínez' && $User->user_name == 'bermi' && $User->email == 'bermi@example.com');118 $this->assertTrue($User->first_name=='Bermi' && $User->last_name == 'Ferrer Mart�nez' && $User->user_name == 'bermi' && $User->email == 'bermi@example.com'); 119 119 120 120 $Users = new AkTestUser(); … … 122 122 123 123 foreach ($FoundUsers as $User){ 124 $expected1 = ($User->first_name=='Hilario' && $User->last_name == 'Herv ás Añó' && $User->user_name == 'hilario' && $User->email == 'hilario@example.com');125 $expected2 = ($User->first_name=='Bermi' && $User->last_name == 'Ferrer Mart ínez' && $User->user_name == 'bermi' && $User->email == 'bermi@example.com');124 $expected1 = ($User->first_name=='Hilario' && $User->last_name == 'Herv�s A��' && $User->user_name == 'hilario' && $User->email == 'hilario@example.com'); 125 $expected2 = ($User->first_name=='Bermi' && $User->last_name == 'Ferrer Mart�nez' && $User->user_name == 'bermi' && $User->email == 'bermi@example.com'); 126 126 $this->assertTrue($expected1 || $expected2); 127 127 } … … 136 136 $Users = new AkTestUser(); 137 137 $User = $Users->find(3, array('conditions' => "user_name = 'bermi'", 'order' => "created_at DESC")); 138 $this->assertTrue($User->first_name=='Bermi' && $User->last_name == 'Ferrer Mart ínez' && $User->user_name == 'bermi' && $User->email == 'bermi@example.com');138 $this->assertTrue($User->first_name=='Bermi' && $User->last_name == 'Ferrer Mart�nez' && $User->user_name == 'bermi' && $User->email == 'bermi@example.com'); 139 139 140 140 141 141 $Users = new AkTestUser(); 142 142 $User = $Users->find('first', array('conditions' => array("user_name = :user_name", ':user_name' => 'hilario'))); 143 $this->assertTrue($User->first_name=='Hilario' && $User->last_name == 'Herv ás Añó' && $User->user_name == 'hilario' && $User->email == 'hilario@example.com');143 $this->assertTrue($User->first_name=='Hilario' && $User->last_name == 'Herv�s A��' && $User->user_name == 'hilario' && $User->email == 'hilario@example.com'); 144 144 145 145 $User = new AkTestUser('first_name=>','test_name','last_name->','A'); … … 162 162 $Users = new AkTestUser(); 163 163 $User = $Users->find('first', array('order' => "last_name ASC", 'offset' => 2)); 164 $this->assertTrue($User->first_name=='Hilario' && $User->last_name == 'Herv ás Añó' && $User->user_name == 'hilario' && $User->email == 'hilario@example.com');164 $this->assertTrue($User->first_name=='Hilario' && $User->last_name == 'Herv�s A��' && $User->user_name == 'hilario' && $User->email == 'hilario@example.com'); 165 165 166 166 $Users = new AkTestUser(); … … 284 284 $this->assertEqual($Got->first_name, 'Jane'); 285 285 286 $Got = $Users->findFirst("last_name = 'Ferrer Mart ínez'");286 $Got = $Users->findFirst("last_name = 'Ferrer Mart�nez'"); 287 287 $this->assertEqual($Got->first_name, 'Bermi'); 288 288 … … 323 323 $Bermi = $Users->find(3); 324 324 $this->assertEqual($Bermi->last_name,'Ferrer'); 325 326 $updates = array(); 327 $updates[5] = array('first_name'=> 'NEWNAME5'); 328 $updates[6] = array('first_name'=> 'NEWNAME6'); 329 $updates[7] = array('first_name'=> 'NEWNAME7'); 330 $Users->update(array_keys($updates), array_values($updates)); 331 332 $FoundUsers = $Users->find(5, 6, 7); 333 334 foreach ($FoundUsers as $FoundUser){ 335 $this->assertEqual($FoundUser->first_name,'NEWNAME'.$FoundUser->getId()); 336 } 337 325 338 326 339 $Users->update(array(5,6,7), array('first_name'=>'NEW TEST NAME')); … … 338 351 $Users = new AkTestUser(); 339 352 $Bermi = $Users->findFirst("first_name = 'Bermi'"); 340 $Bermi->last_name = 'Ferrer Mart ínez';353 $Bermi->last_name = 'Ferrer Mart�nez'; 341 354 $Bermi->createOrUpdate(); 342 355 343 356 $Bermi = $Users->findFirst("first_name = 'Bermi'"); 344 $this->assertEqual($Bermi->last_name,'Ferrer Mart ínez');357 $this->assertEqual($Bermi->last_name,'Ferrer Mart�nez'); 345 358 346 359 $User = new AkTestUser(); 347 360 $User->first_name = 'Vero'; 348 $User->last_name = 'Mach í';361 $User->last_name = 'Mach�'; 349 362 $User->createOrUpdate(); 350 363 351 $Vero = $Users->findFirst("last_name = 'Mach í'");364 $Vero = $Users->findFirst("last_name = 'Mach�'"); 352 365 $this->assertEqual($Vero->first_name,'Vero'); 353 366 } … … 358 371 $Users = new AkTestUser(); 359 372 $Bermi = $Users->findFirst("first_name = 'Bermi'"); 360 $this->assertEqual($Bermi->last_name,'Ferrer Mart ínez');373 $this->assertEqual($Bermi->last_name,'Ferrer Mart�nez'); 361 374 $Bermi->set('last_name','Ferrer'); 362 375 $this->assertEqual($Bermi->last_name,'Ferrer'); 363 376 $Bermi->reload(); 364 $this->assertEqual($Bermi->last_name,'Ferrer Mart ínez');377 $this->assertEqual($Bermi->last_name,'Ferrer Mart�nez'); 365 378 } 366 379 … … 387 400 $Users = new AkTestUser(); 388 401 $Alicia = $Users->findFirst("first_name = 'Alicia'"); 389 $Alicia->updateAttribute('last_name','Sadurn í');402 $Alicia->updateAttribute('last_name','Sadurn�'); 390 403 391 404 $Alicia = $Users->findFirst("first_name = 'Alicia'"); 392 $this->assertTrue($Alicia->last_name == 'Sadurn í');405 $this->assertTrue($Alicia->last_name == 'Sadurn�'); 393 406 394 407 } … … 398 411 $Users = new AkTestUser(); 399 412 $Hilario = $Users->findFirst("first_name = 'Hilario'"); 400 $Hilario->updateAttributes(array('last_name'=>'Herv ás'));413 $Hila
