Show
Ignore:
Timestamp:
02/23/06 20:09:13 (6 years ago)
Author:
john
Message:

added in phpDoc commenting tests docs - Walt

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • trunk/trax/vendor/trax/active_record.php

    r136 r138  
    11<?php 
    2 # $Id$ 
    3 # 
    4 # Copyright (c) 2005 John Peterson 
    5 # 
    6 # Permission is hereby granted, free of charge, to any person obtaining 
    7 # a copy of this software and associated documentation files (the 
    8 # "Software"), to deal in the Software without restriction, including 
    9 # without limitation the rights to use, copy, modify, merge, publish, 
    10 # distribute, sublicense, and/or sell copies of the Software, and to 
    11 # permit persons to whom the Software is furnished to do so, subject to 
    12 # the following conditions: 
    13 # 
    14 # The above copyright notice and this permission notice shall be 
    15 # included in all copies or substantial portions of the Software. 
    16 # 
    17 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
    18 # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 
    19 # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
    20 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 
    21 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 
    22 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 
    23 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
    24  
     2/** 
     3 *  File containing the ActiveRecord class 
     4 * 
     5 *  (PHP 5) 
     6 * 
     7 *  @package PHPonTrax 
     8 *  @version $Id$ 
     9 *  @copyright (c) 2005 John Peterson 
     10 * 
     11 *  Permission is hereby granted, free of charge, to any person obtaining 
     12 *  a copy of this software and associated documentation files (the 
     13 *  "Software"), to deal in the Software without restriction, including 
     14 *  without limitation the rights to use, copy, modify, merge, publish, 
     15 *  distribute, sublicense, and/or sell copies of the Software, and to 
     16 *  permit persons to whom the Software is furnished to do so, subject to 
     17 *  the following conditions: 
     18 * 
     19 *  The above copyright notice and this permission notice shall be 
     20 *  included in all copies or substantial portions of the Software. 
     21 * 
     22 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
     23 *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 
     24 *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
     25 *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 
     26 *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 
     27 *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 
     28 *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
     29 */ 
     30 
     31/** 
     32 *  Load the {@link http://pear.php.net/manual/en/package.pear.php PEAR base class} 
     33 */ 
    2534require_once('PEAR.php'); 
     35 
     36/** 
     37 *  Load the {@link http://pear.php.net/manual/en/package.database.db.php PEAR DB package} 
     38 */ 
    2639require_once('DB.php'); 
    2740 
     41/** 
     42 *  Base class for the ActiveRecord design pattern 
     43 * 
     44 *  <p>Each subclass of this class is associated with a database table 
     45 *  in the Model section of the Model-View-Controller architecture. 
     46 *  By convention, the name of each subclass is the CamelCase singular 
     47 *  form of the table name, which is in the lower_case_underscore 
     48 *  plural notation.  For example,  
     49 *  a table named "order_details" would be associated with a subclass 
     50 *  of ActiveRecord named "OrderDetail", and a table named "people" 
     51 *  would be associated with subclass "Person".</p> 
     52 * 
     53 *  <p>For a discussion of the ActiveRecord design pattern, see 
     54 *  "Patterns of Enterprise  
     55 *  Application Architecture" by Martin Fowler, pp. 160-164.</p> 
     56 * 
     57 *  <p>Unit tester: {@link ActiveRecordTest}</p> 
     58 * 
     59 *  @package PHPonTrax 
     60 */ 
    2861class ActiveRecord { 
    2962 
    30     static private $db = null; # Reference to Pear db object 
     63    /** 
     64     *  Reference to the object returned by PEAR DB::Connect() 
     65     * 
     66     *  @var object DB 
     67     *  <b>FIXME: static should be after private</b> 
     68     */ 
     69    static private $db = null; 
     70 
     71    /** 
     72     *  <b>FIXME: dead code?  Never referenced in ActiveRecord</b><br> 
     73     *  <b>FIXME: static should be after protected</b><br> 
     74     *  <b>FIXME: static variables $rows_per_page, $page, $offset are 
     75     *  not declared.  Declaring them would provide a good place to 
     76     *  document them.  On the other hand, if the intent is to give 
     77     *  the user the ability to page through a result set, these 
     78     *  variables need to go in $_SESSION.</b> 
     79     */ 
    3180    static protected $inflector = null; # object to do class inflection 
     81 
     82    /** 
     83     *  Description of a row in the associated table in the database 
     84     * 
     85     *  <p>Retrieved from the RDBMS by {@link set_content_columns()}. 
     86     *  See {@link  
     87     *  http://pear.php.net/manual/en/package.database.db.db-common.tableinfo.php 
     88     *  DB_common::tableInfo()} for the format.  <b>NOTE:</b> Some 
     89     *  RDBMS's don't return all values.</p> 
     90     * 
     91     *  <p>An additional element 'human_name' is added to each column 
     92     *  by {@link set_content_columns()}.  The actual value contained 
     93     *  in each column is stored in an object variable with the name 
     94     *  given by the 'name' element of the column description for each 
     95     *  column.</p> 
     96     * 
     97     *  <p><b>NOTE:</b>The information from the database about which 
     98     *  columns are primary keys is <b>not used</b>.  Instead, the 
     99     *  primary keys in the table are listed in {@$primary_keys}, 
     100     *  which is maintained independently.</p> 
     101     *  @var string[] 
     102     *  @see $primary_keys 
     103     *  @see quoted_attributes() 
     104     *  @see __set() 
     105     */ 
    32106    public $content_columns = null; # info about each column in the table 
    33     public $table_name = null; # if you want to override table name set this in your model 
    34     public $database_name = null; # if you want to override database name set this in your model 
     107 
     108    /** 
     109     *  Table name 
     110     * 
     111     *  Name of the table in the database associated with the subclass. 
     112     *  Normally set to the pluralized lower case underscore form of 
     113     *  the class name by the constructor.  May be overridden. 
     114     *  @var string 
     115     */ 
     116    public $table_name = null; 
     117 
     118    /** 
     119     *  Database name override 
     120     * 
     121     *  Name of the database to use, if you are not using the value 
     122     *  read from file config/database.ini 
     123     *  @var string 
     124     */ 
     125    public $database_name = null; 
     126 
     127    /** 
     128     *  Mode to use when fetching data from database 
     129     * 
     130     *  See {@link 
     131     *  http://pear.php.net/manual/en/package.database.db.db-common.setfetchmode.php 
     132     *  the relevant PEAR DB class documentation} 
     133     *  @var integer 
     134     */ 
    35135    public $fetch_mode = DB_FETCHMODE_ASSOC; 
     136 
     137    /** 
     138     *  Force reconnect to database 
     139     * 
     140     *  @var boolean 
     141     */ 
    36142    public $force_reconnect = false; # should we force a connection everytime 
    37143    public $index_on = "id"; # find_all returns an array of objects each object index is off of this field 
    38144 
    39145    # Table associations 
     146    /** 
     147     *  @todo Document this API 
     148     *  @var string[] 
     149     */ 
    40150    protected $has_many = null; 
     151 
     152    /** 
     153     *  @todo Document this API 
     154     *  @var string[] 
     155     */ 
    41156    protected $has_one = null; 
     157 
     158    /** 
     159     *  @todo Document this API 
     160     *  @var string[] 
     161     */ 
    42162    protected $has_and_belongs_to_many = null; 
     163 
     164    /** 
     165     *  @todo Document this API 
     166     *  @var string[] 
     167     */ 
    43168    protected $belongs_to = null; 
     169 
     170    /** 
     171     *  @todo Document this API 
     172     *  @var string[] 
     173     */ 
    44174    protected $habtm_attributes = null; 
    45175    protected $save_associations = array(); 
    46176    public $auto_save_associations = true; # where or not to auto save defined associations if set 
    47177 
    48     protected $new_record = true;  # whether or not to create a new record or just update 
     178    /** 
     179     *  Whether this object represents a new record 
     180     * 
     181     *  true => This object was created without reading a row from the 
     182     *          database, so use SQL 'INSERT' to put it in the database. 
     183     *  false => This object was a row read from the database, so use 
     184     *           SQL 'UPDATE' to update database with new values. 
     185     *  @var boolean 
     186     */ 
     187    protected $new_record = true; 
     188 
     189    /** 
     190     *  Names of automatic update timestamp columns 
     191     * 
     192     *  When a row containing one of these columns is updated and 
     193     *  {@link $auto_timestamps} is true, update the contents of the 
     194     *  timestamp columns with the current date and time. 
     195     *  @see $auto_timestamps 
     196     *  @see $auto_create_timestamps 
     197     *  @var string[] 
     198     */ 
    49199    protected $auto_update_timestamps = array("updated_at","updated_on"); 
     200 
     201    /** 
     202     *  Names of automatic create timestamp columns 
     203     * 
     204     *  When a row containing one of these columns is created and 
     205     *  {@link $auto_timestamps} is true, store the current date and 
     206     *  time in the timestamp columns. 
     207     *  @see $auto_timestamps 
     208     *  @see $auto_update_timestamps 
     209     *  @var string[] 
     210     */ 
    50211    protected $auto_create_timestamps = array("created_at","created_on"); 
     212 
     213    /** 
     214     *  SQL aggregate functions that may be applied to the associated 
     215     *  table. 
     216     * 
     217     *  SQL defines aggregate functions AVG, COUNT, MAX, MIN and SUM. 
     218     *  Not all of these functions are implemented by all DBMS's 
     219     *  @var string[] 
     220     */ 
    51221    protected $aggregrations = array("count","sum","avg","max","min"); 
    52222 
    53     public $primary_keys = array("id");  # update / delete where clause keys 
    54     public $rows_per_page_default = 20;  # Pagination rows to display per page 
     223    /** 
     224     *  Primary key of the associated table 
     225     * 
     226     *  Array element(s) name the primary key column(s), as used to 
     227     *  specify the row to be updated or deleted.  To be a primary key 
     228     *  a column must be listed both here and in {@link 
     229     *  $content_columns}.  <b>NOTE:</b>This 
     230     *  field is maintained by hand.  It is not derived from the table 
     231     *  description read from the database. 
     232     *  @var string[] 
     233     *  @see $content_columns 
     234     *  @see find() 
     235     *  @see find_all() 
     236     *  @see find_first() 
     237     */ 
     238    public $primary_keys = array("id"); 
     239 
     240    /** 
     241     *  Default for how many rows to return from {@link find_all()} 
     242     *  @var integer 
     243     */ 
     244    public $rows_per_page_default = 20; 
     245 
     246    /** 
     247     *  @todo Document this API 
     248     */ 
    55249    public $display = 10; # Pagination how many numbers in the list << < 1 2 3 4 > >> 
     250 
     251    /** 
     252     *  Description of non-fatal errors found 
     253     * 
     254     *  For every non-fatal error found, an element describing the 
     255     *  error is added to $errors.  Initialized to an empty array in  
     256     *  {@link valid()} before validating object.  When an error 
     257     *  message is associated with a particular attribute, the message 
     258     *  should be stored with the attribute name as its key.  If the 
     259     *  message is independent of attributes, store it with a numeric 
     260     *  key beginning with 0. 
     261     *   
     262     *  @var string[] 
     263     *  @see add_error() 
     264     *  @see get_errors() 
     265     */ 
    56266    public $errors = array(); 
    57     public $auto_timestamps = true; # whether or not to auto update created_at/on and updated_at/on fields 
     267 
     268    /** 
     269     *  Whether to automatically update timestamps in certain columns 
     270     * 
     271     *  @see $auto_create_timestamps 
     272     *  @see $auto_update_timestamps 
     273     *  @var boolean 
     274     */ 
     275    public $auto_timestamps = true; 
     276 
     277    /** 
     278     *  @todo Document this API 
     279     */ 
    58280    public $auto_save_habtm = true; # auto insert / update $has_and_belongs_to_many tables 
    59281 
    60     # Transactions (only use if your db supports it) 
     282    /** 
     283     *  Transactions (only use if your db supports it) 
     284     *  <b>FIXME: static should be after private</b> 
     285     */ 
    61286    static private $begin_executed = false; # this is for transactions only to let query() know that a 'BEGIN' has been executed 
     287 
     288    /** 
     289     *  <b>FIXME: static should be after public</b> 
     290     */ 
    62291    static public $use_transactions = false; # this will issue a rollback command if any sql fails 
    63292 
    64     # Constructor sets up need parameters for AR to function properly 
     293    /** 
     294     *  Construct an ActiveRecord object 
     295     * 
     296     *  <ol> 
     297     *    <li>Establish a connection to the database</li> 
     298     *    <li>Find the name of the table associated with this object</li> 
     299     *    <li>Read description of this table from the database</li> 
     300     *    <li>Optionally apply update information to column attributes</li> 
     301     *  </ol> 
     302     *  @param string[] $attributes Updates to column attributes 
     303     *  @uses establish_connection() 
     304     *  @uses set_content_columns() 
     305     *  @uses $table_name 
     306     *  @uses set_table_name_using_class_name() 
     307     *  @uses update_attributes() 
     308     */ 
    65309    function __construct($attributes = null) {  
    66310        # Open the database connection 
     
    83327    } 
    84328 
    85     # Override get() if they do $model->some_association->field_name dynamically load the requested 
    86     # contents from the database. 
     329    /** 
     330     *  @todo Document this API 
     331     *  Override get() if they do $model->some_association->field_name 
     332     *  dynamically load the requested contents from the database. 
     333     *  @uses $belongs_to 
     334     *  @uses $has_and_belongs_to_many 
     335     *  @uses $has_many 
     336     *  @uses $has_one 
     337     */ 
    87338    function __get($key) { 
    88339        $association_type = $this->get_association_type($key); 
     
    109360    } 
    110361 
    111     # Override set() if they set certain class variables do some action 
     362    /** 
     363     *  Store column value or description of the table format 
     364     * 
     365     *  If called with key 'table_name', $value is stored as the 
     366     *  description of the table format in $content_columns. 
     367     *  Any other key causes an object variable with the same name to 
     368     *  be created and stored into.  If the value of $key matches the 
     369     *  name of a column in content_columns, the corresponding object 
     370     *  variable becomes the content of the column in this row. 
     371     *  @uses set_content_columns() 
     372     */ 
    112373    function __set($key, $value) { 
    113374        //echo "setting: $key = $value<br>"; 
     
    130391        }          
    131392         
     393    //  Assignment to something else, do it 
    132394        $this->$key = $value; 
    133395    } 
    134396 
    135     # Override call() to dynamically call the database associations 
     397    /** 
     398     *  @todo Document this API 
     399     *  Override call() to dynamically call the database associations 
     400     *  @uses $aggregrations 
     401     *  @uses aggregrate_all() 
     402     *  @uses $belongs_to 
     403     *  @uses $has_one 
     404     *  @uses $has_and_belongs_to_many 
     405     *  @uses $has_many 
     406     *  @uses find_all_by() 
     407     *  @uses find_by() 
     408     */ 
    136409    function __call($method_name, $parameters) { 
    137410        if(method_exists($this,$method_name)) { 
     
    178451    } 
    179452 
    180     # Returns a the name of the join table that would be used for the two 
    181     # tables.  The join table name is decided from the alphabetical order 
    182     # of the two tables.  e.g. "genres_movies" because "g" comes before "m" 
    183     # 
    184     # Parameters: $first_table, $second_table: the names of two database tables, 
    185     #   e.g. "movies" and "genres" 
     453    /** 
     454     *  @todo Document this API 
     455     *  Returns a the name of the join table that would be used for the two 
     456     *  tables.  The join table name is decided from the alphabetical order 
     457     *  of the two tables.  e.g. "genres_movies" because "g" comes before "m" 
     458     * 
     459     *  Parameters: $first_table, $second_table: the names of two database tables, 
     460     *   e.g. "movies" and "genres" 
     461     */ 
    186462    private function get_join_table_name($first_table, $second_table) { 
    187463        $tables = array(); 
     
    192468    } 
    193469 
    194     # Find all records using a "has_and_belongs_to_many" relationship 
    195     # (many-to-many with a join table in between).  Note that you can also 
    196     # specify an optional "paging limit" by setting the corresponding "limit" 
    197     # instance variable.  For example, if you want to return 10 movies from the 
    198     # 5th movie on, you could set $this->movies_limit = "10, 5" 
    199     # 
    200     # Parameters: $this_table_name:  The name of the database table that has the 
    201     #                                one row you are interested in.  E.g. genres 
    202     #             $other_table_name: The name of the database table that has the 
    203     #                                many rows you are interested in.  E.g. movies 
    204     # Returns: An array of ActiveRecord objects. (e.g. Movie objects) 
     470    /** 
     471     *  @todo Document this API 
     472     *  Find all records using a "has_and_belongs_to_many" relationship 
     473     * (many-to-many with a join table in between).  Note that you can also 
     474     *  specify an optional "paging limit" by setting the corresponding "limit" 
     475     *  instance variable.  For example, if you want to return 10 movies from the 
     476     *  5th movie on, you could set $this->movies_limit = "10, 5" 
     477     * 
     478     *  Parameters: $this_table_name:  The name of the database table that has the 
     479     *                                 one row you are interested in.  E.g. genres 
     480     *              $other_table_name: The name of the database table that has the 
     481     *                                 many rows you are interested in.  E.g. movies 
     482     *  Returns: An array of ActiveRecord objects. (e.g. Movie objects) 
     483     */ 
    205484    private function find_all_habtm($other_table_name, $parameters = null) { 
    206485        $other_class_name = Inflector::classify($other_table_name); 
     
    250529    } 
    251530 
    252     # Find all records using a "has_many" relationship (one-to-many) 
    253     # 
    254     # Parameters: $other_table_name: The name of the other table that contains 
    255     #                                many rows relating to this object's id. 
    256     # Returns: An array of ActiveRecord objects. (e.g. Contact objects) 
     531    /** 
     532     *  @todo Document this API 
     533     *  Find all records using a "has_many" relationship (one-to-many) 
     534     * 
     535     *  Parameters: $other_table_name: The name of the other table that contains 
     536     *                                 many rows relating to this object's id. 
     537     *  Returns: An array of ActiveRecord objects. (e.g. Contact objects) 
     538     */ 
    257539    private function find_all_has_many($other_table_name, $parameters = null) { 
    258540        # Prepare the class name and primary key, e.g. if 
     
    304586    } 
    305587 
    306     # Find all records using a "has_one" relationship (one-to-one) 
    307     # (the foreign key being in the other table) 
    308     # Parameters: $other_table_name: The name of the other table that contains 
    309     #                                many rows relating to this object's id. 
    310     # Returns: An array of ActiveRecord objects. (e.g. Contact objects) 
     588    /** 
     589     *  @todo Document this API 
     590     *  Find all records using a "has_one" relationship (one-to-one) 
     591     *  (the foreign key being in the other table) 
     592     *  Parameters: $other_table_name: The name of the other table that contains 
     593     *                                 many rows relating to this object's id. 
     594     *  Returns: An array of ActiveRecord objects. (e.g. Contact objects) 
     595     */ 
    311596    private function find_one_has_one($other_object_name, $parameters = null) { 
    312597        # Prepare the class name and primary key, e.g. if 
     
    332617    } 
    333618 
    334     # Find all records using a "belongs_to" relationship (one-to-one) 
    335     # (the foreign key being in the table itself) 
    336     # Parameters: $other_object_name: The singularized version of a table name. 
    337     #                                 E.g. If the Contact class belongs_to the 
    338     #                                 Customer class, then $other_object_name 
    339     #                                 will be "customer". 
     619    /** 
     620     *  @todo Document this API 
     621     *  Find all records using a "belongs_to" relationship (one-to-one) 
     622     *  (the foreign key being in the table itself) 
     623     *  Parameters: $other_object_name: The singularized version of a table name. 
     624     *                                  E.g. If the Contact class belongs_to the 
     625     *                                  Customer class, then $other_object_name 
     626     *                                  will be "customer". 
     627     */ 
    340628    private function find_one_belongs_to($other_object_name, $parameters = null) { 
    341629        # Prepare the class name and primary key, e.g. if 
     
    361649    } 
    362650 
    363     # Used to run all the the *_all() aggregrate functions such as count_all() sum_all() 
    364     # Return the result of the aggregration or 0. 
     651    /** 
     652     *  Implement *_all() functions (SQL aggregate functions) 
     653     * 
     654     *  Apply one of the SQL aggregate functions to a column of the 
     655     *  table associated with this object.  The SQL aggregate 
     656     *  functions are AVG, COUNT, MAX, MIN and SUM.  Not all DBMS's 
     657     *  implement all of these functions. 
     658     *  @param string $agrregrate_type SQL aggregate function to 
     659     *    apply, suffixed '_all'.  The aggregate function is one of 
     660     *  the strings in {@link $aggregrations}.  
     661     *  @param string[] $parameters  Conditions to apply to the 
     662     *    aggregate function.  If present, must be an array of three 
     663     *    strings:<ol> 
     664     *     <li>$parameters[0]: If present, expression to apply 
     665     *       the aggregate function to.  Otherwise, '*' will be used. 
     666     *       <b>NOTE:</b>SQL uses '*' only for the COUNT() function, 
     667     *       where it means "including rows with NULL in this column".</li> 
     668     *     <li>$parameters[1]: argument to WHERE clause</li> 
     669     *     <li>$parameters[2]: joins??? @todo Document this parameter</li> 
     670     *    </ol> 
     671     *  @throws {@link ActiveRecordError} 
     672     *  @uses query() 
     673     *  @uses is_error() 
     674     */ 
    365675    private function aggregrate_all($aggregrate_type, $parameters = null) { 
    366676        $aggregrate_type = strtoupper(substr($aggregrate_type, 0, -4)); 
     
    387697    } 
    388698 
    389     # Return if this is a new record or not. 
    390     function is_new_record() { 
     699    /** 
     700     *  Test whether this object represents a new record 
     701     *  @uses $new_record 
     702     *  @return boolean Whether this object represents a new record 
     703     */ 
     704   function is_new_record() { 
    391705        return $this->new_record; 
    392706    } 
    393707 
    394     # get the attributes for a specific column. 
     708   /** 
     709    *  @todo Document this API 
     710    *  get the attributes for a specific column. 
     711    *  @uses $content_columns 
     712    */ 
    395713    function column_for_attribute($attribute) { 
    396714        if(is_array($this->content_columns)) { 
     
    404722    } 
    405723     
    406     # checks if a column exists or not in the table 
     724    /** 
     725     *  checks if a column exists or not in the table 
     726     */ 
    407727    function column_attribute_exists($attribute) { 
    408728        if(is_array($this->content_columns)) { 
     
    416736    } 
    417737 
    418     # Returns PEAR result set of one record with only the passed in column in the result set. 
     738    /** 
     739     *  @todo Document this API 
     740     *  Returns PEAR result set of one record with only the passed in column in the result set. 
     741     * 
     742     *  @uses $db 
     743     *  @throws {@link ActiveRecordError} 
     744     *  @uses is_error() 
     745     */ 
    419746    function send($column) { 
    420747        if($this->column_attribute_exists($column)) { 
     
    428755    } 
    429756 
    430     # Only used if you want to do transactions and your db supports transactions 
     757    /** 
     758     *  @todo Document this API 
     759     * Only used if you want to do transactions and your db supports transactions 
     760     * 
     761     *  @uses $db 
     762     */ 
    431763    function begin() { 
    432764        self::$db->query("BEGIN"); 
     
    434766    } 
    435767 
    436     # Only used if you want to do transactions and your db supports transactions 
     768    /** 
     769     *  @todo Document this API 
     770     *  Only used if you want to do transactions and your db supports transactions 
     771     * 
     772     *  @uses $db 
     773     */ 
    437774    function commit() { 
    438775        self::$db->query("COMMIT");  
     
    440777    } 
    441778 
    442     # Only used if you want to do transactions and your db supports transactions 
     779    /** 
     780     *  @todo Document this API 
     781     *  Only used if you want to do transactions and your db supports transactions 
     782     * 
     783     *  @uses $db 
     784     */ 
    443785    function rollback() { 
    444786        self::$db->query("ROLLBACK"); 
    445787    } 
    446788 
    447     # Uses PEAR::DB's query to run the query and returns the DB result set 
     789    /** 
     790     *  Perform an SQL query and return the results 
     791     * 
     792     *  @param string $sql  SQL for the query command 
     793     *  @return mixed {@link http://pear.php.net/manual/en/package.database.db.db-result.php object DB_result} 
     794     *    Result set from query 
     795     *  @uses $db 
     796     *  @uses is_error() 
     797     *  @throws {@link ActiveRecordError} 
     798     */ 
    448799    function query($sql) { 
    449800        # Run the query 
     
    458809    } 
    459810 
    460     # *Magical* function that is dynamically built according to you. 
    461     # Works like find_all() or find().   
    462     # Example: 
    463     #   $im_an_object = $model->find_by_fname("John"); 
    464     #   $im_an_array_of_objects = $model->find_all_by_fname_and_state("John","UT");  
     811    /** 
     812     *  Implement find_by_*() and find_all_by_* methods 
     813     *   
     814     *  Converts a method name beginning 'find_by_' or 'find_all_by_' 
     815     *  into a query for rows matching the rest of the method name and 
     816     *  the arguments to the function.  The part of the method name 
     817     *  after '_by' is parsed for columns and logical relationships 
     818     *  (AND and OR) to match.  For example, the call 
     819     *    find_by_fname('Ben') 
     820     *  is converted to 
     821     *    SELECT * ... WHERE fname='Ben' 
     822     *  and the call 
     823     *    find_by_fname_and_lname('Ben','Dover') 
     824     *  is converted to 
     825     *    SELECT * ... WHERE fname='Ben' AND lname='Dover' 
     826     *   
     827     *  @uses find_all() 
     828     *  @uses find_first() 
     829     */ 
    465830    private function find_by($method_name, $parameters, $find_all = false) { 
    466831    $method_parts = explode("_",substr($method_name, ($find_all ? 12 : 8))); 
     
    471836            $or_cnt = substr_count(strtolower($method_name), "_or_"); 
    472837            $part_size = count($method_parts) - $and_cnt - $or_cnt; 
     838            // FIXME: This loop doesn't work right for either 
     839        // find_by_first_name_and_last_name or 
     840        // find_all_by_first_name_and_last_name 
    473841            foreach($method_parts as $part) { 
    474842                if(strtoupper($part) == "AND") { 
     
    500868    } 
    501869 
    502     # This will return all the records matched by the options used.  
    503     # If no records are found, an empty array is returned. 
     870    /** 
     871     *  Return rows selected by $conditions 
     872     * 
     873     *  If no rows match, an empty array is returned. 
     874     *  @param string $conditions SQL to use in the query.  If 
     875     *    $conditions contains "SELECT", then $orderings, $limit and 
     876     *    $joins are ignored and the query is completely specified by 
     877     *    $conditions.  If $conditions is omitted or does not contain 
     878     *    "SELECT", "SELECT * FROM" will be used.  If $conditions is 
     879     *    specified and does not contain "SELECT", the query will 
     880     *    include "WHERE $conditions".  If $conditions is null, the 
     881     *    entire table is returned. 
     882     *  @param string $orderings Argument to "ORDER BY" in query. 
     883     *    If specified, the query will include 
     884     *    "ORDER BY $orderings". If omitted, no ordering will be 
     885     *    applied.   
     886     *  @param integer[] $limit Page, rows per page??? 
     887     *  @todo Document the $limit and $joins parameters 
     888     *  @param string $joins ??? 
     889     *  @uses $rows_per_page_default 
     890     *  @uses $rows_per_page 
     891     *  @uses $offset 
     892     *  @uses $page 
     893     *  @uses is_error() 
     894     *  @uses $new_record 
     895     *  @uses query() 
     896     *  @return object[] Array of objects of the same class as this 
     897     *    object, one object for each row returned by the query. 
     898     *    If the column 'id' was in the results, it is used as the key 
     899     *    for that object in the array. 
     900     *  @throws {@link ActiveRecordError} 
     901     */ 
    504902    function find_all($conditions = null, $orderings = null, $limit = null, $joins = null) { 
    505903        if (is_array($limit)) { 
     
    565963    } 
    566964 
    567     # This can either be a specific id (1), or an array of ids (array(5, 6, 10)).  
    568     # If no record can be found for Returns an object if id isn't an array otherwise  
    569     # returns an array of objects. 
     965    /** 
     966     *  Find row(s) with specified value(s) 
     967     * 
     968     *  Find all the rows in the table which match the argument $id. 
     969     *  Return zero or more objects of the same class as this 
     970     *  class representing the rows that matched the argument. 
     971     *  @param mixed[] $id  If $id is an array then a query will be 
     972     *    generated selecting all of the array values in column "id". 
     973     *    If $id is a string containing "=" then the string value of 
     974     *    $id will be inserted in a WHERE clause in the query.  If $id 
     975     *    is a scalar not containing "=" then a query will be generated  
     976     *    selecting the first row WHERE id = '$id'. 
     977     *    <b>NOTE</b> The column name "id" is used regardless of the 
     978     *    value of {@link $primary_keys}.  Therefore if you need to 
     979     *    select based on some column other than "id", you must pass a 
     980     *    string argument ready to insert in the SQL SELECT. 
     981     *  @param string $orderings Argument to "ORDER BY" in query. 
     982     *    If specified, the query will include "ORDER BY 
     983     *    $orderings". If omitted, no ordering will be applied. 
     984     *  @param integer[] $limit Page, rows per page??? 
     985     *  @param string $joins ??? 
     986     *  @todo Document the $limit and $joins parameters 
     987     *  @uses find_all() 
     988     *  @uses find_first() 
     989     *  @return mixed Results of query.  If $id was a scalar then the 
     990     *    result is an object of the same class as this class and 
     991     *    matching $id conditions, or if no row matched the result is 
     992     *    null.  
     993     * 
     994     *    If $id was an array then the result is an array containing 
     995     *    objects of the same class as this class and matching the 
     996     *    conditions set by $id.  If no rows matched, the array is 
     997     *    empty. 
     998     *  @throws {@link ActiveRecordError} 
     999     */ 
    5701000    function find($id, $orderings = null, $limit = null, $joins = null) { 
    5711001        if(is_array($id)) { 
     
    5841014    } 
    5851015 
    586     # This will return the first record matched by the options used.  
    587     # These options can either be specific conditions or merely an order.  
    588     # If no record can matched, false is returned. 
     1016    /** 
     1017     *  Return first row selected by $conditions 
     1018     * 
     1019     *  If no rows match, null is returned. 
     1020     *  @param string $conditions SQL to use in the query.  If 
     1021     *    $conditions contains "SELECT", then $orderings, $limit and 
     1022     *    $joins are ignored and the query is completely specified by 
     1023     *    $conditions.  If $conditions is omitted or does not contain 
     1024     *    "SELECT", "SELECT * FROM" will be used.  If $conditions is 
     1025     *    specified and does not contain "SELECT", the query will 
     1026     *    include "WHERE $conditions".  If $conditions is null, the 
     1027     *    entire table is returned. 
     1028     *  @param string $orderings Argument to "ORDER BY" in query. 
     1029     *    If specified, the query will include 
     1030     *    "ORDER BY $orderings". If omitted, no ordering will be 
     1031     *    applied.   
     1032     *  FIXME This parameter doesn't seem to make sense 
     1033     *  @param integer[] $limit Page, rows per page??? @todo Document this parameter 
     1034     *  FIXME This parameter doesn't seem to make sense 
     1035     *  @param string $joins ??? @todo Document this parameter 
     1036     *  @uses find_all() 
     1037     *  @return mixed An object of the same class as this class and 
     1038     *    matching $conditions, or null if none did. 
     1039     *  @throws {@link ActiveRecordError} 
     1040     */ 
    5891041    function find_first($conditions, $orderings = null, $limit = null, $joins = null) { 
    5901042        $result = $this->find_all($conditions, $orderings, $limit, $joins); 
     
    5921044    } 
    5931045 
    594     # Works like find_all(), but requires a complete SQL string. 
     1046    /** 
     1047     *  Return all the rows selected by the SQL argument 
     1048     * 
     1049     *  If no rows match, an empty array is returned. 
     1050     *  @param string $sql SQL to use in the query. 
     1051     */ 
    5951052    function find_by_sql($sql) { 
    5961053        return $this->find_all($sql); 
    5971054    } 
    5981055 
    599     # Reloads the attributes of this object from the database. 
     1056    /** 
     1057     *  @todo Document this API 
     1058     *  Reloads the attributes of this object from the database. 
     1059     *  @uses get_primary_key_conditions() 
     1060     */ 
    6001061    function reload($conditions = null) { 
    6011062        if(is_null($conditions)) { 
     
    6121073    } 
    6131074 
    614     # Loads into current object values from the database. 
     1075    /** 
     1076     *  Loads into current object values from the database. 
     1077     */ 
    6151078    function load($conditions = null) { 
    6161079        return $this->reload($conditions);         
    6171080    } 
    6181081 
    619     # Creates an object, instantly saves it as a record (if the validation permits it). 
    620     # If the save fails under validations it returns false and $errors array gets set. 
     1082    /** 
     1083     *  @todo Document this API.  What's going on here?  It appears to 
     1084     *        either create a row with all empty values, or it tries 
     1085     *        to recurse once for each attribute in $attributes. 
     1086     *  FIXME: resolve calling sequence 
     1087     *  Creates an object, instantly saves it as a record (if the validation permits it). 
     1088     *  If the save fails under validations it returns false and $errors array gets set. 
     1089     */ 
    6211090    function create($attributes, $dont_validate = false) { 
    6221091        if(is_array($attributes)) { 
     
    6311100    } 
    6321101 
    633     # Finds the record from the passed id, instantly saves it with the passed attributes  
    634     # (if the validation permits it). Returns true on success and false on error. 
     1102    /** 
     1103     *  @todo Document this API 
     1104     *  Finds the record from the passed id, instantly saves it with the passed attributes  
     1105     *  (if the validation permits it). Returns true on success and false on error. 
     1106     */ 
    6351107    function update($id, $attributes, $dont_validate = false) { 
    6361108        if(is_array($id)) { 
     
    6441116    } 
    6451117 
    646     # Updates all records with the SET-part of an SQL update statement in updates and  
    647     # returns an integer with the number of rows updates. A subset of the records can  
    648     # be selected by specifying conditions.  
    649     # Example: 
    650     #   $model->update_all("category = 'cooldude', approved = 1", "author = 'John'"); 
     1118    /** 
     1119     *  @todo Document this API 
     1120     *  Updates all records with the SET-part of an SQL update statement in updates and  
     1121     *  returns an integer with the number of rows updates. A subset of the records can  
     1122     *  be selected by specifying conditions.  
     1123     *  Example: 
     1124     *    $model->update_all("category = 'cooldude', approved = 1", "author = 'John'"); 
     1125     *  @uses is_error() 
     1126     *  @uses query() 
     1127     *  @throws {@link ActiveRecordError} 
     1128     */ 
    6511129    function update_all($updates, $conditions = null) { 
    6521130        $sql = "UPDATE $this->table_name SET $updates WHERE $conditions"; 
     
    6591137    } 
    6601138 
    661     # Save without valdiating anything. 
     1139    /** 
     1140     *  @todo Document this API 
     1141     *  Save without valdiating anything. 
     1142     */ 
    6621143    function save_without_validation($attributes = null) { 
    6631144        return $this->save($attributes, true); 
    6641145    } 
    6651146 
    666     # $attributes is an array passed in from the html form usually. Where key is the column name 
    667     # and value is the new value to INSERT or UPDATE in the database.   
     1147    /** 
     1148     *  Create or update a row in the table with specified attributes 
     1149     * 
     1150     *  @param string[] $attributes List of name => value pairs giving 
     1151     *    name and value of attributes to set. 
     1152     *  @param boolean $dont_validate true => Don't call validation 
     1153     *    routines before saving the row.  If false or omitted, all  
     1154     *    applicable validation routines are called. 
     1155     *  @uses add_record_or_update_record() 
     1156     *  @uses update_attributes() 
     1157     *  @uses valid() 
     1158     *  @return boolean 
     1159     *          <ul> 
     1160     *            <li>true => row was updated or inserted successfully</li> 
     1161     *            <li>false => insert failed</li> 
     1162     *          </ul> 
     1163     */ 
    6681164    function save($attributes = null, $dont_validate = false) { 
    6691165        if(!is_null($attributes)) { 
     
    6771173    } 
    6781174 
    679     # Just determines if this save should be an INSERT or an UPDATE 
     1175    /** 
     1176     *  Create or update a row in the table 
     1177     * 
     1178     *  If this object represents a new row in the table, insert it. 
     1179     *  Otherwise, update the exiting row.  before_?() and after_?() 
     1180     *  routines will be called depending on whether the row is new. 
     1181     *  @uses add_record() 
     1182     *  @uses after_create() 
     1183     *  @uses after_update() 
     1184     *  @uses before_create() 
     1185     *  @uses before_save() 
     1186     *  @uses $new_record 
     1187     *  @uses update_record() 
     1188     *  @return boolean 
     1189     *          <ul> 
     1190     *            <li>true => row was updated or inserted successfully</li> 
     1191     *            <li>false => insert failed</li> 
     1192     *          </ul> 
     1193     */ 
    6801194    private function add_record_or_update_record() {  
    6811195        $this->before_save(); 
     
    6931207    } 
    6941208 
    695     # Add a record in the table represented by this model 
     1209    /** 
     1210     *  Insert a new row in the table associated with this object 
     1211     * 
     1212     *  Build an SQL INSERT statement getting the table name from 
     1213     *  {@link $table_name}, the column names from {@link 
     1214     *  $content_columns} and the values from object variables. 
     1215     *  Send the insert to the RDBMS. 
     1216     *  FIXME: Shouldn't we be saving the insert ID value as an object 
     1217     *  variable $this->id? 
     1218     *  @uses $auto_save_habtm 
     1219     *  @uses add_habtm_records() 
     1220     *  @uses before_create() 
     1221     *  @uses get_insert_id() 
     1222     *  @uses is_error() 
     1223     *  @uses query() 
     1224     *  @uses quoted_attributes() 
     1225     *  @uses raise() 
     1226     *  @uses $table_name 
     1227     *  @return boolean 
     1228     *          <ul> 
     1229     *            <li>true => row was inserted successfully</li> 
     1230     *            <li>false => insert failed</li> 
     1231     *          </ul> 
     1232     *  @throws {@link ActiveRecordError} 
     1233     */ 
    6961234    private function add_record() { 
    6971235        $attributes = $this->quoted_attributes(); 
     
    7151253    } 
    7161254 
    717     # Updates a record in the table represented by this model 
     1255    /** 
     1256     *  Update the row in the table described by this object 
     1257     * 
     1258     *  The primary key attributes must exist and have appropriate 
     1259     *  non-null values.  If a column is listed in {@link 
     1260     *  $content_columns} but no attribute of that name exists, the 
     1261     *  column will be set to the null string ''. 
     1262     *  @todo Describe habtm automatic update 
     1263     *  @uses is_error() 
     1264     *  @uses get_updates_sql() 
     1265     *  @uses get_primary_key_conditions() 
     1266     *  @uses query() 
     1267     *  @uses raise() 
     1268     *  @uses update_habtm_records() 
     1269     *  @return boolean 
     1270     *          <ul> 
     1271     *            <li>true => row was updated successfully</li> 
     1272     *            <li>false => update failed</li> 
     1273     *          </ul> 
     1274     *  @throws {@link ActiveRecordError} 
     1275     */ 
    7181276    private function update_record() { 
    7191277        $updates = $this->get_updates_sql(); 
     
    7351293    } 
    7361294     
    737     # returns the association type if defined in child class or null 
     1295    /** 
     1296     *  @todo Document this API 
     1297     *  returns the association type if defined in child class or null 
     1298     */ 
    7381299    function get_association_type($association_name) { 
    7391300        $type = null; 
     
    7771338    } 
    7781339     
    779     # Saves any associations objects assigned to this instance 
     1340    /** 
     1341     *  @todo Document this API 
     1342     *  Saves any associations objects assigned to this instance 
     1343     */ 
    7801344    private function save_associations() {       
    7811345        if(count($this->save_associations) && $this->auto_save_associations) { 
     
    7961360    } 
    7971361     
    798     # save the association to the database 
     1362    /** 
     1363     *  @todo Document this API 
     1364     *  save the association to the database 
     1365     */ 
    7991366    private function save_association($object, $type) { 
    8001367        if(is_object($object) && get_parent_class($object) == __CLASS__ && $type) { 
     
    8121379    } 
    8131380 
    814     # Deletes the record with the given $id or if you have done a 
    815     # $model = $model->find($id), then $model->delete() it will delete 
    816     # the record it just loaded from the find() without passing anything 
    817     # to delete(). If an array of ids is provided, all ids in array are deleted. 
     1381    /** 
     1382     *  @todo Document this API 
     1383     *  Deletes the record with the given $id or if you have done a 
     1384     *  $model = $model->find($id), then $model->delete() it will delete 
     1385     *  the record it just loaded from the find() without passing anything 
     1386     *  to delete(). If an array of ids is provided, all ids in array are deleted. 
     1387     *  @uses $errors 
     1388     */ 
    8181389    function delete($id = null) { 
    8191390        if($this->id > 0 && is_null($id)) { 
     
    8331404    } 
    8341405 
    835     # Deletes all the records that matches the $conditions 
    836     # Example: 
    837     # $model->delete_all("person_id = 2 AND (category = 'Toasters' OR category = 'Microwaves')"); 
     1406    /** 
     1407     *  Delete from table all rows that match argument 
     1408     * 
     1409     *  Delete the row(s), if any, matching the argument. 
     1410     *  @param string $conditions SQL argument to "WHERE" describing 
     1411     *                the rows to delete 
     1412     *  @return boolean 
     1413     *          <ul> 
     1414     *            <li>true => One or more rows were deleted</li> 
     1415     *            <li>false => $conditions was omitted</li> 
     1416     *          </ul> 
     1417     *  @uses is_error() 
     1418     *  @uses $new_record 
     1419     *  @uses $errors 
     1420     *  @uses query() 
     1421     *  @throws {@link ActiveRecordError} 
     1422     */ 
    8381423    function delete_all($conditions = null) { 
    8391424        if(is_null($conditions)) { 
     
    8471432        } 
    8481433 
     1434        //  <b>FIXME: We don't know whether this row was deleted. 
     1435        //    What are the implications of making this a new record?</b> 
    8491436        $this->id = 0; 
    8501437        $this->new_record = true; 
     
    8521439    } 
    8531440 
     1441    /** 
     1442     *  @todo Document this API 
     1443     *  
     1444     *  @uses $has_and_belongs_to_many 
     1445     */ 
    8541446    private function set_habtm_attributes($attributes) { 
    8551447        if(is_array($attributes)) { 
     
    8711463    } 
    8721464 
     1465    /** 
     1466     * 
     1467     *  @todo Document this API 
     1468     */ 
    8731469    private function update_habtm_records($this_foreign_value) { 
    8741470        return $this->add_habtm_records($this_foreign_value); 
    8751471    } 
    8761472 
     1473    /** 
     1474     * 
     1475     *  @todo Document this API 
     1476     *  @uses is_error() 
     1477     *  @uses query() 
     1478     *  @throws {@link ActiveRecordError} 
     1479     */ 
    8771480    private function add_habtm_records($this_foreign_value) { 
    8781481        if($this_foreign_value > 0 && count($this->habtm_attributes) > 0) { 
     
    9031506    } 
    9041507 
     1508    /** 
     1509     *  @todo Document this API 
     1510     * 
     1511     *  @uses is_error() 
     1512     *  @uses query() 
     1513     *  @throws {@link ActiveRecordError} 
     1514     */ 
    9051515    private function delete_habtm_records($this_foreign_value) { 
    9061516        if($this_foreign_value > 0 && count($this->habtm_attributes) > 0) { 
     
    9201530    } 
    9211531 
    922     # Checks to see if $auto_timestamps is true, If yes and there exists a field 
    923     # with a name in matching a name in the auto_create_timestamps or auto_update_timestamps arrays 
    924     # then it will return a valid datetime format to insert/update into the database. 
    925     # This is only called from quoted_attributes(). 
     1532    /** 
     1533     *  Apply automatic timestamp updates 
     1534     * 
     1535     *  If automatic timestamps are in effect (as indicated by 
     1536     *  {@link $auto_timestamps} == true) and the column named in the 
     1537     *  $field argument is of type "timestamp" and matches one of the 
     1538     *  names in {@link auto_create_timestamps} or {@link 
     1539     *  auto_update_timestamps}(as selected by {@link $new_record}), 
     1540     *  then return the current date and  time as a string formatted 
     1541     *  to insert in the database.  Otherwise return $value. 
     1542     *  @uses $new_record 
     1543     *  @uses $content_columns 
     1544     *  @uses $auto_timestamps 
     1545     *  @uses $auto_create_timestamps 
     1546     *  @uses $auto_update_timestamps 
     1547     *  @param string $field Name of a column in the table 
     1548     *  @param mixed $value Value to return if $field is not an 
     1549     *                      automatic timestamp column 
     1550     *  @return mixed Current date and time or $value 
     1551     */ 
    9261552    private function check_datetime($field, $value) { 
    9271553        if($this->auto_timestamps) { 
     
    9411567    } 
    9421568 
    943     # Updates all the attributes(class vars representing the table columns) 
    944     # from the passed array $attributes. 
     1569    /** 
     1570     *  Update object attributes from list in argument 
     1571     *  @param string[] $attributes List of name => value pairs giving 
     1572     *    name and value of attributes to set. 
     1573     *  @todo Figure out and document how datetime fields work 
     1574     */ 
    9451575    function update_attributes($attributes) { 
    9461576        foreach($attributes as $field => $value) { 
     
    9881618    } 
    9891619 
    990     # If $this->set_content_columns() was previously called, which will mean that 
    991     # $content_columns will be an array of containing the column info about the database 
    992     # table this model is representing.  This will return an array where the keys 
    993     # the column names and the values are the values from those columns.   
     1620    /** 
     1621     *  Return pairs of column-name:column-value 
     1622     * 
     1623     *  Return the contents of the object as an array of elements 
     1624     *  where the key is the column name and the value is the column 
     1625     *  value.  Relies on a previous call to 
     1626     *  {@link set_content_columns()} for information about the format 
     1627     *  of a row in the table. 
     1628     *  @uses $content_columns 
     1629     *  @see set_content_columns 
     1630     *  @see quoted_attributes() 
     1631     */ 
    9941632    function get_attributes() { 
    9951633        $attributes = array(); 
     
    10031641    } 
    10041642 
    1005     # Returns an array of all the table columns with the key being the 
    1006     # the database column name and the value being the database column 
    1007     # value.  The value will be single quoted if appropriate. 
     1643    /** 
     1644     *  Return pairs of column-name:quoted-column-value 
     1645     * 
     1646     *  Return pairs of column-name:quoted-column-value where the key 
     1647     *  is the column name and the value is the column value with 
     1648     *  automatic timestamp updating applied and characters special to 
     1649     *  SQL quoted. 
     1650     *   
     1651     *  If $attributes is null or omitted, return all columns as 
     1652     *  currently stored in {@link content_columns()}.  Otherwise, 
     1653     *  return the name:value pairs in $attributes. 
     1654     *  @param string[] $attributes Name:value pairs to return. 
     1655     *    If null or omitted, return the column names and values 
     1656     *    of the object as stored in $content_columns. 
     1657     *  @return string[]  
     1658     *  @uses get_attributes() 
     1659     *  @see set_content_columns() 
     1660     */ 
    10081661    function quoted_attributes($attributes = null) { 
    10091662        if(is_null($attributes)) { 
     
    10271680    } 
    10281681 
    1029     # Returns an a string in the format to put into a WHERE clause for updating 
    1030     # or deleting records.  It builds the clause from the $primary_keys array. 
    1031     # Example: 
    1032     #   $primary_keys = array("id", "ssn"); would be turned into the string 
    1033     #   "id = '5' AND ssn = '555-55-5555'" 
     1682    /** 
     1683     *  Return argument for a "WHERE" clause specifying this row 
     1684     * 
     1685     *  Returns a string which specifies the column(s) and value(s) 
     1686     *  which describe the primary key of this row of the associated 
     1687     *  table.  The primary key must be one or more attributes of the 
     1688     *  object and must be listed in {@link $content_columns} as 
     1689     *  columns in the row. 
     1690     * 
     1691     *  Example: if $primary_keys = array("id", "ssn") and column "id" 
     1692     *  has value "5" and column "ssn" has value "123-45-6789" then 
     1693     *  the string "id = '5' AND ssn = '123-45-6789'" would be returned. 
     1694     *  @uses $primary_keys 
     1695     *  @uses quoted_attributes() 
     1696     *  @return string Column name = 'value' [ AND name = 'value']... 
     1697     */ 
    10341698    function get_primary_key_conditions() { 
    10351699        $conditions = null; 
     
    10521716    } 
    10531717 
    1054     # Returns an a string in the format to put into the SET-part of an SQL update statement 
    1055     # Should return a string formated for the UPDATE.  
    1056     # Example: 
    1057     #   "id = '5', ssn = '555-55-5555'" 
     1718    /** 
     1719     *  Return column values of object formatted for SQL update statement 
     1720     * 
     1721     *  Return a string containing the column names and values of this 
     1722     *  object in a format ready to be inserted in a SQL UPDATE 
     1723     *  statement.  Automatic update has been applied to timestamps if 
     1724     *  enabled and characters special to SQL have been quoted. 
     1725     *  @uses quoted_attributes() 
     1726     *  @return string Column name = 'value', ... for all attributes 
     1727     */ 
    10581728    function get_updates_sql() { 
    10591729        $updates = null; 
     
    10721742    } 
    10731743 
    1074     # Sets the $table_name varible from the class name of the child object (the Model) 
    1075     # used in all queries throughout ActiveRecord 
     1744    /** 
     1745     *  Set {@link $table_name} from the class name of this object 
     1746     * 
     1747     *  By convention, the name of the database table represented by 
     1748     *  this object is derived from the name of the class. 
     1749     *  @uses Inflector::tableize() 
     1750     */ 
    10761751    function set_table_name_using_class_name() { 
    10771752        if(!$this->table_name) { 
     
    10801755    } 
    10811756 
    1082     # Populates the model object with information about the table it represents 
     1757    /** 
     1758     *  Populate object with information about the table it represents  
     1759     * 
     1760     *  Call {@link  
     1761     *  http://pear.php.net/manual/en/package.database.db.db-common.tableinfo.php 
     1762     *  DB_common::tableInfo()} to get a description of the table and 
     1763     *  store it in {@link $content_columns}.  Add a more human 
     1764     *  friendly name to the element for each column. 
     1765     *  <b>FIXME: should throw an exception if tableInfo() fails</b> 
     1766     *  @uses $db 
     1767     *  @uses $content_columns 
     1768     *  @uses Inflector::humanize() 
     1769     *  @see __set() 
     1770     *  @param string $table_name  Name of table to get information about 
     1771     */ 
    10831772    function set_content_columns($table_name) { 
    10841773        $this->content_columns = self::$db->tableInfo($table_name); 
     
    10911780    } 
    10921781 
    1093     # Returns the autogenerated id from the last insert query 
     1782    /** 
     1783     *  Returns the autogenerated id from the last insert query 
     1784     * 
     1785     *  @uses $db 
     1786     *  @uses is_error() 
     1787     *  @uses raise() 
     1788     *  @throws {@link ActiveRecordError} 
     1789     */ 
    10941790    function get_insert_id() { 
    10951791        $id = self::$db->getOne("SELECT LAST_INSERT_ID();"); 
     
    11001796    } 
    11011797 
    1102     # Calls DB::Connect() to open a database connection. It uses $GLOBALS['TRAX_DB_SETTINGS'][TRAX_MODE]  
    1103     # If it finds a connection in ACTIVE_RECORD_DB it uses it. 
     1798    /** 
     1799     *  Open a database connection if one is not currently open 
     1800     * 
     1801     *  The name of the database normally comes from 
     1802     *  $GLOBALS['TRAX_DB_SETTINGS'] which is set in {@link 
     1803     *  environment.php} by reading file config/database.ini. The 
     1804     *  database name may be overridden by assigning a different name 
     1805     *  to {@link $database_name}.  
     1806     *   
     1807     *  If there is a connection now open, as indicated by the saved 
     1808     *  value of a DB object in $GLOBALS['ACTIVE_RECORD_DB'], and 
     1809     *  {@link force_reconnect} is not true, then set the database 
     1810     *  fetch mode and return. 
     1811     * 
     1812     *  If there is no connection, open one and save a reference to 
     1813     *  it in $GLOBALS['ACTIVE_RECORD_DB']. 
     1814     * 
     1815     *  @uses $db 
     1816     *  @uses $database_name 
     1817     *  @uses $force_reconnect 
     1818     *  @uses is_error() 
     1819     *  @throws {@link ActiveRecordError} 
     1820     */ 
    11041821    function establish_connection() { 
    11051822        # Connect to the database and throw an error if the connect fails. 
     
    11291846    } 
    11301847 
    1131     # Tests to see if an object is either a PEAR Error or a DB Error object. 
     1848    /** 
     1849     *  Test whether argument is a PEAR Error object or a DB Error object. 
     1850     * 
     1851     *  @param object $obj Object to test 
     1852     *  @return boolean  Whether object is one of these two errors 
     1853     */ 
    11321854    function is_error($obj) { 
    11331855        if((PEAR::isError($obj)) || (DB::isError($obj))) { 
     
    11381860    } 
    11391861 
     1862    /** 
     1863     *  Throw an exception describing an error in this object 
     1864     * 
     1865     *  @throws {@link ActiveRecordError} 
     1866     */ 
    11401867    function raise($message) { 
    11411868        $error_message  = "Model Class: ".get_class($this)."<br>"; 
     
    11441871    } 
    11451872 
    1146     # Add an error to Active Record 
     1873    /** 
     1874     *  Add or overwrite description of an error to the list of errors 
     1875     *  @param string $error Error message text 
     1876     *  @param string $key Key to associate with the error (in the 
     1877     *    simple case, column name).  If omitted, numeric keys will be 
     1878     *    assigned starting with 0.  If specified and the key already 
     1879     *    exists in $errors, the old error message will be overwritten 
     1880     *    with the value of $error. 
     1881     *  @uses $errors 
     1882     */ 
    11471883    function add_error($error, $key = null) { 
    11481884        if(!is_null($key))  
     
    11521888    } 
    11531889 
    1154     # Return the errors array or if the first param is true then 
    1155     # returns it as a string seperated by the second param. 
     1890    /** 
     1891     *  Return description of non-fatal errors 
     1892     * 
     1893     *  @uses $errors 
     1894     *  @param boolean $return_string 
     1895     *    <ul> 
     1896     *      <li>true => Concatenate all error descriptions into a string 
     1897     *        using $seperator between elements and return the 
     1898     *        string</li> 
     1899     *      <li>false => Return the error descriptions as an array</li> 
     1900     *    </ul> 
     1901     *  @param string $seperator  String to concatenate between error 
     1902     *    descriptions if $return_string == true 
     1903     *  @return mixed Error description(s), if any 
     1904     */ 
    11561905    function get_errors($return_string = false, $seperator = "<br>") { 
    11571906        if($return_string && count($this->errors) > 0) { 
     
    11621911    } 
    11631912 
    1164     # Return errors as a string. 
     1913    /** 
     1914     *  Return errors as a string. 
     1915     * 
     1916     *  Concatenate all error descriptions into a stringusing 
     1917     *  $seperator between elements and return the string. 
     1918     *  @param string $seperator  String to concatenate between error 
     1919     *    descriptions 
     1920     *  @return string Concatenated error description(s), if any 
     1921     */ 
    11651922    function get_errors_as_string($seperator = "<br>") { 
    11661923        return $this->get_errors(true, $seperator); 
    11671924    } 
    11681925 
    1169     # Runs validate and validate_on_create or validate_on_update  
    1170     # and returns true if no errors were added otherwise false. 
     1926    /** 
     1927     *  Runs validation routines for update or create 
     1928     * 
     1929     *  @uses after_validation(); 
     1930     *  @uses after_validation_on_create(); 
     1931     *  @uses after_validation_on_update(); 
     1932     *  @uses before_validation(); 
     1933     *  @uses before_validation_on_create(); 
     1934     *  @uses before_validation_on_update(); 
     1935     *  @uses $errors 
     1936     *  @uses $new_record 
     1937     *  @uses validate(); 
     1938     *  @uses validate_model_attributes(); 
     1939     *  @uses validate_on_create();  
     1940     *  @return boolean  
     1941     *    <ul> 
     1942     *      <li>true => Valid, no errors found. 
     1943     *        {@link $errors} is empty</li> 
     1944     *      <li>false => Not valid, errors in {@link $errors}</li> 
     1945     *    </ul> 
     1946     */ 
    11711947    function valid() { 
    11721948        # first clear the errors array 
     
    11941970    } 
    11951971 
    1196     # Successively calls all functions that begin with "validate_" to 
    1197     # validate each field.  The "validate_*" functions should return an 
    1198     # array whose first element is true or false (indicating whether or 
    1199     # not the validation succeeded), and whose second element is the 
    1200     # error message to display on validation failure. 
    1201     # 
    1202     # Parameters: none 
    1203     # 
    1204     # Returns: true if all validations succeeded, false otherwise 
     1972    /** 
     1973     *  Call every method named "validate_*()" where * is a column name 
     1974     * 
     1975     *  Find and call every method named "validate_something()" where 
     1976     *  "something" is the name of a column.  The "validate_something()" 
     1977     *  functions are expected to return an array whose first element 
     1978     *  is true or false (indicating whether or not the validation 
     1979     *  succeeded), and whose second element is the error message to 
     1980     *  display if the first element is false. 
     1981     * 
     1982     *  @return boolean  
     1983     *    <ul> 
     1984     *      <li>true => Valid, no errors found. 
     1985     *        {@link $errors} is empty</li> 
     1986     *      <li>false => Not valid, errors in {@link $errors}. 
     1987     *        $errors is an array whose keys are the names of columns, 
     1988     *        and the value of each key is the error message returned 
     1989     *        by the corresponding validate_*() method.</li> 
     1990     *    </ul> 
     1991     *  @uses $errors 
     1992     *  @uses get_attributes() 
     1993     */ 
    12051994    function validate_model_attributes() { 
    12061995        $validated_ok = true; 
     
    12372026    } 
    12382027 
    1239     # Overwrite this method for validation checks on all saves and 
    1240     # use $this->errors[] = "My error message."; or 
    1241     # for invalid attributes $this->errors['attribute'] = "Attribute is invalid."; 
     2028    /** 
     2029     *  @todo Document this API 
     2030     *  Overwrite this method for validation checks on all saves and 
     2031     *  use $this->errors[] = "My error message."; or 
     2032     *  for invalid attributes $this->errors['attribute'] = "Attribute is invalid."; 
     2033     */ 
    12422034    function validate() {} 
    12432035 
    1244     # Override this method for validation checks used only on creation. 
     2036    /** 
     2037     *  @todo Document this API 
     2038     *  Override this method for validation checks used only on creation. 
     2039     */ 
    12452040    function validate_on_create() {} 
    12462041 
    1247     # Override this method for validation checks used only on updates. 
     2042    /** 
     2043     *  @todo Document this API 
     2044     *  Override this method for validation checks used only on updates. 
     2045     */ 
    12482046    function validate_on_update() {} 
    12492047 
    1250     # Is called before validate(). 
     2048    /** 
     2049     *  @todo Document this API 
     2050     *  Is called before validate(). 
     2051     */ 
    12512052    function before_validation() {} 
    12522053 
    1253     # Is called after validate(). 
     2054    /** 
     2055     *  @todo Document this API 
     2056     *  Is called after validate(). 
     2057     */ 
    12542058    function after_validation() {} 
    12552059 
    1256     # Is called before validate() on new objects that haven't been saved yet (no record exists). 
     2060    /** 
     2061     *  @todo Document this API 
     2062     *  Is called before validate() on new objects that haven't been saved yet (no record exists). 
     2063     */ 
    12572064    function before_validation_on_create() {} 
    12582065 
    1259     # Is called after validate() on new objects that haven't been saved yet (no record exists). 
     2066    /** 
     2067     *  @todo Document this API 
     2068     *  Is called after validate() on new objects that haven't been saved yet (no record exists). 
     2069     */ 
    12602070    function after_validation_on_create()  {} 
    12612071 
    1262     # Is called before validate() on existing objects that has a record. 
     2072    /** 
     2073     *  @todo Document this API 
     2074     *  Is called before validate() on existing objects that has a record. 
     2075     */ 
    12632076    function before_validation_on_update() {} 
    12642077 
    1265     # Is called after validate() on existing objects that has a record. 
     2078    /** 
     2079     *  @todo Document this API 
     2080     *  Is called after validate() on existing objects that has a record. 
     2081     */ 
    12662082    function after_validation_on_update()  {} 
    12672083 
    1268     # Is called before save() (regardless of whether its a create or update save). 
     2084    /** 
     2085     *  @todo Document this API 
     2086     *  Is called before save() (regardless of whether its a create or update save) 
     2087     */ 
    12692088    function before_save() {} 
    12702089 
    1271     # Is called after save (regardless of whether its a create or update save). 
     2090    /** 
     2091     *  @todo Document this API 
     2092     *  Is called after save (regardless of whether its a create or update save). 
     2093     */ 
    12722094    function after_save() {} 
    12732095 
    1274     # Is called before save() on new objects that havent been saved yet (no record exists). 
     2096    /** 
     2097     *  @todo Document this API 
     2098     *  Is called before save() on new objects that havent been saved yet (no record exists). 
     2099     */ 
    12752100    function before_create() {} 
    12762101 
    1277     # Is called after save() on new objects that havent been saved yet (no record exists). 
     2102    /** 
     2103     *  @todo Document this API 
     2104     *  Is called after save() on new objects that havent been saved yet (no record exists). 
     2105     */ 
    12782106    function after_create() {} 
    12792107 
    1280     # Is called before save() on existing objects that has a record. 
     2108    /** 
     2109     *  @todo Document this API 
     2110     *  Is called before save() on existing objects that has a record. 
     2111     */ 
    12812112    function before_update() {} 
    12822113 
    1283     # Is called after save() on existing objects that has a record. 
     2114    /** 
     2115     *  @todo Document this API 
     2116     *  Is called after save() on existing objects that has a record. 
     2117     */ 
    12842118    function after_update() {} 
    12852119 
    1286     # Is called before delete(). 
     2120    /** 
     2121     *  @todo Document this API 
     2122     *  Is called before delete(). 
     2123     */ 
    12872124    function before_delete() {} 
    12882125 
    1289     # Is called after delete(). 
     2126    /** 
     2127     *  @todo Document this API 
     2128     *  Is called after delete(). 
     2129     */ 
    12902130    function after_delete() {} 
    12912131 
    1292     ######################################################################### 
    1293     # Paging html functions 
    1294  
     2132    /** 
     2133     *  @todo Document this API 
     2134     * Paging html functions 
     2135     */ 
    12952136    function limit_select($controller =null, $additional_query = null) { 
    12962137        if($this->pages > 0) { 
     
    13092150    } 
    13102151 
     2152    /** 
     2153     *  @todo Document this API 
     2154     * 
     2155     */ 
    13112156    function page_list(){ 
    13122157        $page_list  = "";