Ignore:
Timestamp:
09/26/13 15:41:49 (11 years ago)
Author:
angelo
Message:

Ticket #3491 - Compatibilizar Expresso com novas versoes do PHP

File:
1 edited

Legend:

Unmodified
Added
Removed
  • sandbox/2.5.1-evolucao/phpgwapi/inc/adodb/docs/docs-active-record.htm

    r34 r8222  
    1515<body> 
    1616<h1>ADOdb Active Record</h1> 
    17 <p> (c) 2000-2007 John Lim (jlim#natsoft.com)</p> 
     17<p> (c) 2000-2010 John Lim (jlim#natsoft.com)</p> 
    1818<p><font size="1">This software is dual licensed using BSD-Style and LGPL. This  
    1919  means you can use it in compiled proprietary and commercial products.</font></p> 
     
    3333<li>NewADOConnection::GetActiveRecords() and ADOConnection::GetActiveRecordsClass() functions in adodb.inc.php.<p> 
    3434<li>Caching of table metadata so it is only queried once per table, no matter how many Active Records are created.<p> 
    35 <li>The additional functionality is described <a href=#additional>below</a>.  
     35<li>PHP5 version of ADOdb_Active_Record now supports <a href=#onetomany>one-to-many</a> relationships.<p> 
     36<li>New adodb-active-recordx.inc.php, which is an <a href=#recordx>Active Record eXtended</a> implementation that support JOINs for higher performance when loading children, and other nice features.<p> 
     37<li>Lots of  <a href=#additional>additional functionality</a>.<p>  
    3638</ul> 
    3739<P> 
     
    6769 </pre>    
    6870<p> 
    69 ADOdb_Active_Record's are object representations of table rows. Each table in the database is represented by a class in PHP. To begin working with a table as a ADOdb_Active_Record, a class that extends ADOdb_Active_Records needs to be created for it. 
    70  
    71 <pre> 
    72 class Person extends ADOdb_Active_Record{} 
    73 $person = new Person(); 
     71ADOdb_Active_Records are object representations of table rows. Each table in the database is represented by a class in PHP. To begin working with a table as a ADOdb_Active_Record, a class that extends ADOdb_Active_Record needs to be created for it. 
     72 
     73<pre> 
     74class person extends ADOdb_Active_Record{} 
     75$person = new person(); 
    7476</pre>    
    7577 
    7678<p> 
    77 In the above example, a new ADOdb_Active_Record object $person was created to access the "persons" table. Zend_Db_DataObject takes the name of the class, pluralizes it (according to American English rules), and assumes that this is the name of the table in the database. 
     79In the above example, a new ADOdb_Active_Record object $person was created to access the "persons" table. Zend_Db_DataObject takes the name of the class, pluralizes it (according to American English rules), and assumes that this is the name of the table in the database. Also note that with MySQL, table names are case-sensitive, so your class name must match the table name's case. With other databases with case-insensitive tables, your class can be capitalized differently. 
    7880<p> 
    7981This kind of behavior is typical of ADOdb_Active_Record. It will assume as much as possible by convention rather than explicit configuration. In situations where it isn't possible to use the conventions that ADOdb_Active_Record expects, options can be overridden as we'll see later. 
     
    110112To insert a new record into the database, change the object's properties and then call the ADOdb_Active_Record::save() method: 
    111113<pre> 
    112 $person = new Person(); 
    113 $person->nameFirst = 'Andi'; 
    114 $person->nameLast  = 'Gutmans'; 
     114$person = new person(); 
     115$person->name_first = 'Andi'; 
     116$person->name_last  = 'Gutmans'; 
    115117$person->save(); 
    116118 </pre>    
     
    118120Oh, no! The above code snippet does not insert a new record into the database. Instead, outputs an error: 
    119121<pre> 
    120 1048: Column 'name_first' cannot be null 
     1221048: Column 'favorite_color' cannot be null 
    121123 </pre>    
    122124<p> 
     
    131133 * this $person into the database table. 
    132134 */ 
    133 $person = new Person(); 
     135$person = new person(); 
    134136$person->name_first     = 'Andi'; 
    135137$person->name_last      = 'Gutmans'; 
     
    161163<h3><li>Setting the Table Name</h3> 
    162164<p>The default behaviour on creating an ADOdb_Active_Record is to "pluralize" the class name and 
    163  use that as the table name. Often, this is not the case. For example, the Person class could be reading  
     165 use that as the table name. Often, this is not the case. For example, the person class could be reading  
    164166 from the "People" table.  
    165167<p>We provide two ways to define your own table: 
    166168<p>1. Use a constructor parameter to override the default table naming behaviour. 
    167169<pre> 
    168         class Person extends ADOdb_Active_Record{} 
    169         $person = new Person('People'); 
     170        class person extends ADOdb_Active_Record{} 
     171        $person = new person('People'); 
    170172</pre> 
    171173<p>2. Define it in a class declaration: 
    172174<pre> 
    173         class Person extends ADOdb_Active_Record 
     175        class person extends ADOdb_Active_Record 
    174176        { 
    175177        var $_table = 'People'; 
    176178        } 
    177         $person = new Person(); 
     179        $person = new person(); 
    178180</pre> 
    179181 
     
    189191<pre> 
    190192$ADODB_ASSOC_CASE = 0; 
    191 $person = new Person('People'); 
     193$person = new person('People'); 
    192194$person->name = 'Lily'; 
    193195$ADODB_ASSOC_CASE = 2; 
    194 $person2 = new Person('People'); 
     196$person2 = new person('People'); 
    195197$person2->NAME = 'Lily';  
    196198</pre> 
     
    229231<p>We want to retrieve an array of active records based on some search criteria. For example: 
    230232<pre> 
    231 class Person extends ADOdb_Active_Record { 
     233class person extends ADOdb_Active_Record { 
    232234var $_table = 'people'; 
    233235} 
    234236 
    235 $person = new Person(); 
    236 $peopleArray =& $person->Find("name like ? order by age", array('Sm%')); 
    237 </pre> 
     237$person = new person(); 
     238$peopleArray = $person->Find("name like ? order by age", array('Sm%')); 
     239</pre> 
     240 
     241<h3><li>Quoting Identifiers</h3> 
     242<p>You can force column names to be quoted in INSERT and UPDATE statements, typically because you are using reserved words as column names by setting 
     243<pre> 
     244ADODB_Active_Record::$_quoteNames = true; 
     245</pre> 
     246<p>Default is false. 
    238247 
    239248<h3><li>Error Handling and Debugging</h3> 
     
    260269 
    261270# PHP4 or PHP5 without enabling exceptions 
    262 $obj =& new ADOdb_Active_Record('Products'); 
     271$obj = new ADOdb_Active_Record('Products'); 
    263272if ($obj->ErrorMsg()){ 
    264273        echo $obj->ErrorMsg(); 
     
    271280include('adodb-exceptions.inc.php'); 
    272281try { 
    273         $obj =& new ADOdb_Active_Record('Products'); 
     282        $obj = new ADOdb_Active_Record('Products'); 
    274283        $obj->Set($row); 
    275284} catch(exceptions $e) { 
     
    281290<p> 
    282291ADOdb_Active_Record does not require the table to have a primary key. You can insert records for such a table, but you will not be able to update nor delete.  
    283 <p>Sometimes you are retrieving data from a view or table that has no primary key, but has a unique index. You can dynamically set the primary key of a table through the constructor, or using ADOdb_Active_Record::SetPrimaryKeys(): 
     292<p>Sometimes you are retrieving data from a view or table that has no primary key, but has a unique index. You can dynamically set the primary key of a table through the constructor: 
    284293<pre> 
    285294        $pkeys = array('category','prodcode'); 
     
    288297        $rec = new ADOdb_Active_Record('Products', $pkeys); 
    289298         
    290          // or use method 
    291         $rec->SetPrimaryKeys($pkeys); 
     299        // or define a new class 
     300        class Product extends ADOdb_Active_Record { 
     301                function __construct() 
     302                { 
     303                        parent::__construct('Products', array('prodid')); 
     304                } 
     305        } 
     306         
     307        $rec = new Product(); 
    292308</pre> 
    293309 
     
    298314<h3><li>Dealing with Multiple Databases</h3> 
    299315<p> 
    300 Sometimes we want to load  data from one database and insert it into another using ActiveRecords. This can be done using the optional parameter of the ADOdb_Active_Record constructor. In the following example, we read data from db.table1 and store it in db2.table2: 
     316Sometimes we want to load data from one database and insert it into another using ActiveRecords. This can be done using the optional parameter of the ADOdb_Active_Record constructor. In the following example, we read data from db.table1 and store it in db2.table2: 
    301317<pre> 
    302318$db = NewADOConnection(...); 
     
    320336$rec = new ADOdb_Active_Record("table1",array("id"),$db2); 
    321337</pre> 
    322  
     338<p>You can now give a named label in SetDatabaseAdapter, allowing to determine in your class definition which database to load, using var $_dbat. 
     339<pre> 
     340$db1 = NewADOConnection(...); // some ADOdb DB 
     341ADOdb_Active_Record::SetDatabaseAdapter($db1, 'mysql'); 
     342$db2 = NewADOConnection(...); // some ADOdb DB 
     343ADOdb_Active_Record::SetDatabaseAdapter($db2, 'oracle'); 
     344 
     345class FooRecord extends ADOdb_Active_Record 
     346{ 
     347<b>var $_dbat = 'mysql';</b>  // uses 'mysql' connection 
     348... 
     349} 
     350</pre> 
    323351<h3><li>$ADODB_ACTIVE_CACHESECS</h3> 
    324352<p>You can cache the table metadata (field names, types, and other info such primary keys) in $ADODB_CACHE_DIR (which defaults to /tmp) by setting 
     
    335363 } 
    336364</pre> 
    337 Of course a SELECT statement is superior because it's simpler and much more efficient (probably by a factor of x10 or more): 
     365Of course an UPDATE statement is superior because it's simpler and much more efficient (probably by a factor of x10 or more): 
    338366<pre> 
    339367   $db->Execute("update Products set price = price * 1.1 where category='Furniture'"); 
    340368</pre> 
    341 <p>Another issue is performance. For performance sensitive code, using direct SQL will always be faster than using Active Records due to overhead and the fact that all fields in a row are retrieved (rather than only the subset you need) whenever an Active Record is loaded. 
     369<p>For performance sensitive code, using direct SQL will always be faster than using Active Records due to overhead and the fact that all fields in a row are retrieved (rather than only the subset you need) whenever an Active Record is loaded. 
    342370 
    343371<h3><li>Transactions</h3> 
     
    354382</pre> 
    355383 
     384<a name=onetomany> 
     385<h2>One to Many Relations</h2> 
     386<p>Since ADOdb 5.06, we support parent child relationships. This is done using the ClassBelongsTo() and ClassHasMany() functions.  
     387<a name=tablehasmany> 
     388<h3><li>ClassHasMany</h3> 
     389<p>To globally define a one-to-many relationship we use the static function ADODB_Active_Record::ClassHasMany($class, $relation, $foreignKey = '', $foreignClass = 'ADODB_Active_Record'). For example, we have 2 tables, <strong>persons</strong> (parent table) and <strong>children</strong> (child table) 
     390linked by <strong>persons.id = children.person_id</strong>. The variable $person->children is an array that holds the children. To define this relationship: 
     391<pre> 
     392        class person extends ADOdb_Active_Record{} 
     393        ADODB_Active_Record::ClassHasMany('person', 'children','person_id'); 
     394         
     395        $person = new person(); 
     396        $person->Load("id=1"); 
     397        foreach($person->children as $c) { 
     398                echo " $c->name_first "; 
     399                $c->name_first .= ' K.'; 
     400                $c->Save();  ## each child record must be saved individually 
     401        } 
     402</pre> 
     403<p>If no data is loaded, then children is set to an empty array: 
     404<pre> 
     405        $person2 = new person(); 
     406        $p = $person2->children;  ## $p is an empty array() 
     407</pre> 
     408<P>By default, data returned by HasMany() is unsorted. To define an order by clause (or define a SELECT LIMIT window), see <a href=#loadrelations>LoadRelations()</a> below. Another point is that all children are loaded only when the child member is accessed (in __get), and not when the Load() function of the parent object is called. This helps to conserve memory. 
     409 
     410<p>To create and save new parent and child records: 
     411<pre> 
     412 
     413        class person extends ADOdb_Active_Record{} 
     414        class children extends ADOdb_Active_Record{} 
     415        ADODB_Active_Record::ClassHasMany('person', 'children','person_id'); 
     416         
     417        $person = new person(); 
     418         
     419        for ($i=0; $i<10; $i++)  
     420                $person->children[0] = new children('children'); 
     421          
     422         // modify fields of $person, then... 
     423        $person->save(); 
     424         
     425        foreach($person->children as $c) { 
     426                // modify fields of $c then... 
     427                $c->save(); 
     428        } 
     429</pre> 
     430<p>You can have multiple relationships (warning: relations are case-sensitive, 'Children' !== 'children'): 
     431<pre> 
     432        ADODB_Active_Record::ClassHasMany('person', 'children','person_id'); 
     433        ADODB_Active_Record::ClassHasMany('person', 'siblings','person_id'); 
     434        $person = new person(); 
     435        $person->Load('id=1'); 
     436        var_dump($person->children); 
     437        var_dump($person->siblings); 
     438</pre> 
     439<p>By default, the child class is ADOdb_Active_Record. Sometimes you might want the child class to be based on your own class which has additional functions. You can do so using the last parameter: 
     440<pre> 
     441        class person extends ADOdb_Active_Record{} 
     442        class child extends ADOdb_Active_Record { .... some modifications here ... } 
     443        ADODB_Active_Record::ClassHasMany('person', 'children','person_id', 'child'); 
     444</pre> 
     445<p>Lastly some troubleshooting issues. We use the __get() method to set  
     446$p->children below. So once $p->children is defined by accessing it, we don't change the child reference, as shown below: 
     447<pre> 
     448        ADODB_Active_Record::ClassHasMany('person', 'children','person_id'); 
     449        $p = new person(); 
     450        $p->Load('id=1'); 
     451        # $p->children points to person_id = 1 
     452        var_dump($p->children); 
     453         
     454        $p->Load('id=2'); 
     455        # $p->children still points to person_id = 1 
     456        var_dump($p->children);  
     457</pre> 
     458<p>The solution to the above is to unset($p->children) before $p->Load('id=2'). 
     459<h3><li>TableHasMany</h3> 
     460For some classes, the mapping between class name and table name (which is the pluralised version) might not match. For example,  
     461the class name might be <b>person</b>, but the table name might be <b>people</b>. So we have 2 tables, <strong>people</strong> (parent table) and <strong>children</strong> (child table) 
     462linked by <strong>people.id = children.person_id</strong>. 
     463<p>Then you use the following static function 
     464 ADODB_Active_Record::TableHasMany($table, $relation, $foreignKey = '', $foreignClass = 'ADODB_Active_Record') like this: 
     465<pre> 
     466ADODB_Active_Record::TableHasMany('people', 'children', 'person_id') 
     467</pre> 
     468<h3><li>TableKeyHasMany</h3> 
     469For some classes, the mapping between class name and table name (which is the pluralised version) might not match or the primary key is not the default <b>id</b>. For example,  
     470the class name might be <b>person</b>, but the table name might be <b>people</b>. So we have 2 tables, <strong>people</strong> (parent table) and <strong>children</strong> (child table) 
     471linked by <strong>people.pid = children.person_id</strong>. 
     472<p>Then you use the following static function 
     473 ADODB_Active_Record::TableKeyHasMany($table, $tablePKey, $relation, $foreignKey = '', $foreignClass = 'ADODB_Active_Record') like this: 
     474<pre> 
     475ADODB_Active_Record::TableKeyHasMany('people', 'pid', 'children', 'person_id') 
     476</pre> 
     477 
     478 
     479<h3><li>A Complete ClassHasMany example</h3> 
     480<p>Here is sample usage using mysql: 
     481<pre> 
     482        include_once('../adodb.inc.php'); 
     483        include_once('../adodb-active-record.inc.php'); 
     484 
     485        $db = NewADOConnection('mysql://root@localhost/northwind'); 
     486        ADOdb_Active_Record::SetDatabaseAdapter($db); 
     487 
     488        $db->Execute("CREATE TEMPORARY TABLE `persons` ( 
     489                        `id` int(10) unsigned NOT NULL auto_increment, 
     490                        `name_first` varchar(100) NOT NULL default '', 
     491                        `name_last` varchar(100) NOT NULL default '', 
     492                        `favorite_color` varchar(100) NOT NULL default '', 
     493                        PRIMARY KEY  (`id`) 
     494                    ) ENGINE=MyISAM; 
     495                   "); 
     496                            
     497        $db->Execute("CREATE TEMPORARY TABLE `children` ( 
     498                        `id` int(10) unsigned NOT NULL auto_increment, 
     499                                        `person_id` int(10) unsigned NOT NULL, 
     500                                        `gender` varchar(10) default 'F', 
     501                        `name_first` varchar(100) NOT NULL default '', 
     502                        `name_last` varchar(100) NOT NULL default '', 
     503                        `favorite_pet` varchar(100) NOT NULL default '', 
     504                        PRIMARY KEY  (`id`) 
     505                    ) ENGINE=MyISAM; 
     506                   "); 
     507                            
     508        $db->Execute("insert into children (person_id,name_first,name_last) values (1,'Jill','Lim')"); 
     509        $db->Execute("insert into children (person_id,name_first,name_last) values (1,'Joan','Lim')"); 
     510        $db->Execute("insert into children (person_id,name_first,name_last) values (1,'JAMIE','Lim')"); 
     511                            
     512        class person extends ADOdb_Active_Record{} 
     513        ADODB_Active_Record::ClassHasMany('person', 'children','person_id');     
     514         
     515        $person = new person(); 
     516         
     517        $person->name_first     = 'John'; 
     518        $person->name_last      = 'Lim'; 
     519        $person->favorite_color = 'lavender'; 
     520        $person->save(); // this save will perform an INSERT successfully 
     521         
     522        $person2 = new person(); # no need to define HasMany() again, adodb remembers definition 
     523        $person2->Load('id=1'); 
     524         
     525        $c = $person2->children; 
     526        if (is_array($c) && sizeof($c) == 3 && $c[0]->name_first=='Jill' && $c[1]->name_first=='Joan' 
     527                && $c[2]->name_first == 'JAMIE') echo "OK Loaded HasMany&lt;br>"; 
     528        else { 
     529                echo "Error loading hasMany should have 3 array elements Jill Joan Jamie&lt;br>"; 
     530        } 
     531</pre> 
     532 
     533<h3><li>HasMany</h3> 
     534<p>This older method is deprecated and ClassHasMany/TableHasMany/TableKeyHasMany should be used.  
     535<p>The older way to define a one-to-many relationship is to use $parentobj->HasMany($relation, $foreignKey = ''). For example, we have 2 tables, <strong>persons</strong> (parent table) and <strong>children</strong> (child table) 
     536linked by <strong>persons.id = children.person_id</strong>. The variable $person->children is an array that holds the children. To define this relationship: 
     537<pre> 
     538        class person extends ADOdb_Active_Record{} 
     539         
     540        $person = new person(); 
     541        $person->HasMany('children','person_id'); 
     542        $person->Load("id=1"); 
     543        foreach($person->children as $c) { 
     544                echo " $c->name_first "; 
     545                $c->name_first .= ' K.'; 
     546                $c->Save();  ## each child record must be saved individually 
     547        } 
     548</pre> 
     549<p>This HasMany() definition is global for the current script. This means that you only need to define it once. In the following example, $person2 knows about <em>children</em>. 
     550<pre> 
     551        $person = new person(); 
     552        $person->HasMany('children','person_id'); 
     553         
     554        $person2 = new person(); 
     555        $person->Load("id=1"); 
     556        $p = $person2->children; 
     557</pre> 
     558 
     559 
     560<h3><li>ClassBelongsTo</h3> 
     561<p>You can define the parent of the current object using ADODB_Active_Record::ClassBelongsTo($class, $relationName, $foreignKey, $parentPrimaryKey = 'id', $parentClass = 'ADODB_Active_Record'). In the example below, 
     562we have a child table <strong>kids</strong>, and a parent table <strong>person</strong>. We have a link <strong>kids.person_id = persons.id</strong>. We create a child first, then link it to the parent: 
     563<pre> 
     564        class kid extends ADOdb_Active_Record{}; 
     565        ADODB_Active_Record::ClassBelongsTo('kid','person','person_id','id');  
     566 
     567        $ch = new kid(); // default tablename will be 'kids', with primary key 'id'  
     568        $ch->Load('id=1'); 
     569        $p = $ch->person; 
     570        if (!$p || $p->name_first != 'John') echo "Error loading belongsTo&lt;br>"; 
     571        else echo "OK loading BelongTo&lt;br>"; 
     572</pre> 
     573<p> 
     574<p>Note that relationships are case-sensitive, so ClassBelongsTo('kid','PARENT', 'parent_id') and ClassBelongsTo('kid', 'parent', 'parent_id') are not the same.  
     575<p>Also if no data is loaded into the child instance, then $p will return null; 
     576<pre> 
     577        ADODB_Active_Record::ClassBelongsTo('kid','person','person_id','id');  
     578         
     579        $ch = new kid(); 
     580        $p = $ch->person; # $p is null 
     581</pre> 
     582<p>Another way to define the class of the parent (which otherwise defaults to ADODB_Active_Record) as follows: 
     583<pre> 
     584 
     585        class kid extends ADOdb_Active_Record{}; 
     586        class person extends ADOdb_Active_Record{... your modifications ... }; 
     587        ADODB_Active_Record::ClassBelongsTo('kid','person','person_id','id', 'person');  
     588</pre> 
     589<h3><li>TableBelongsTo</h3> 
     590<p>If the child table differs from the convention that the child table name is the plural of the child class name, use this function: 
     591ADODB_Active_Record::TableBelongsTo($childTable, $relationName, $foreignKey, $parentPrimaryKey = 'id', $parentClass = 'ADODB_Active_Record'). 
     592<p>E.g. the class is <b>child</b>, but the table name is <b>children</b>, and the link between the two tables is children.person_id = person.id: 
     593<pre> 
     594        ADODB_Active_Record::TableBelongsTo('children','person','person_id','id'); 
     595</pre> 
     596<h3><li>TableKeyBelongsTo</h3> 
     597<p>If the child table differs from the convention that the child table name is the plural of the child class name or the primary key is not 'id', use this function: 
     598ADODB_Active_Record::TableKeyBelongsTo($childTable, $childKey, $relationName, $foreignKey, $parentPrimaryKey = 'id', $parentClass = 'ADODB_Active_Record'). 
     599<p>E.g. the class is <b>child</b>, but the table name is <b>children</b> and primary key is <b>ch_id</b>, and the link between the two tables is children.person_id = person.id: 
     600<pre> 
     601        ADODB_Active_Record::TableKeyBelongsTo('children','ch_id', 'person','person_id','id'); 
     602</pre> 
     603<h3><li>BelongsTo</h3> 
     604<p>The following is deprecated. Use ClassBelongsTo/TableBelongsTo/TableKeyBelongsTo instead. 
     605<p>The older way to define the parent of the current object is using BelongsTo($relationName, $foreignKey, $parentPrimaryKey = 'id'). In the example below, 
     606we have a child table <strong>children</strong>, and a parent table <strong>person</strong>. We have a link <strong>children.person_id = persons.id</strong>. We create a child first, then link it to the parent: 
     607<pre> 
     608        class Child extends ADOdb_Active_Record{}; 
     609        $ch = new Child('children',array('id')); 
     610        $ch->BelongsTo('person','person_id','id');  ## this can be simplified to $ch->BelongsTo('person') 
     611                                                    ## as foreign key defaults to $table.'_id' and  
     612                                                    ## parent pkey defaults to 'id'  
     613        $ch->Load('id=1'); 
     614        $p = $ch->person; 
     615        if (!$p || $p->name_first != 'John') echo "Error loading belongsTo&lt;br>"; 
     616        else echo "OK loading BelongTo&lt;br>"; 
     617</pre> 
     618<p>You only need to define BelongsTo() once in a script as it is global for all instances.  
     619<a name=loadrelations> 
     620<h3><li>LoadRelations</h3> 
     621<p>Sometimes you want to load only a subset of data in a relationship. For example, you could load all female children sorted by children.name 
     622using LoadRelations($relation, $whereOrderBy = '', $offset = -1, $limit = -1): 
     623<pre> 
     624        # assume this has been called:  
     625        #   ADODB_Active_Record::ClassHasMany('person', 'children','person_id'); 
     626        $person = new person();  
     627        $person->Load('id=23');   
     628        # Load doesn't load children until $person->children is accessed or LoadRelations is called: 
     629        $person->LoadRelations('children',"gender='F' order by name"); 
     630</pre> 
     631<p>Lastly, if you have lots of child data, you can define a window of data of records to load. In the following 
     632example, we load a window of 100 records at a time: 
     633<pre> 
     634 
     635        # assume this has been called:  
     636        #  ADODB_Active_Record::ClassHasMany('Account', 'transactions','account_id');  
     637        $acc = new Account(); 
     638        $acc->Load('id=23'); 
     639         
     640        $start = 0; 
     641        while(true) { 
     642                $acc->LoadRelations('transactions',"tx_done=0 order by trxdate", $start, $start+100); 
     643                if (!$acc->transactions) break; 
     644                foreach ($acc->transactions as $k => $trx) { 
     645                        ## process 
     646                        $trx->tx_done = 1; 
     647                        $trx->save(); 
     648                } 
     649                $start += 100; 
     650                unset($acc->transactions); 
     651 
     652 
     653        } 
     654</pre> 
     655<p>The $offset is 0-based, and $limit is the number of records to retrieve. The default is to ignore $offset (-1) and $limit (-1). 
     656<h3><li>Acknowledgements</h3> 
     657<p>Thanks to Chris Ravenscroft for original one-to-many code (chris#voilaweb.com). 
    356658<h2>ADOConnection Supplement</h2> 
    357659 
     
    372674<pre> 
    373675$whereOrderBy = "1=1 ORDER BY Name"; 
    374 $activeRecArr = $db->ADOdb_Active_Records($table); 
     676$activeRecArr = $db->GetActiveRecords($table); 
    375677</pre> 
    376678<p> 
     
    390692This allows you to retrieve an array of objects derived from ADOdb_Active_Records. Returns false if an error occurs. 
    391693<pre> 
    392 class Product extends ADOdb_Active_Records{}; 
     694class Product extends ADOdb_Active_Record{}; 
    393695$table = 'products'; 
    394696$whereOrderBy = "name LIKE 'A%' ORDER BY Name"; 
     
    419721<h3><li>ADOConnection::ErrorNo()</h3> 
    420722<p>Returns last error number. 
    421 <h2>Code Sample</h2> 
     723 
     724<h2>ActiveRecord Code Sample</h2> 
    422725<p>The following works with PHP4 and PHP5 
    423726<pre> 
     
    441744           "); 
    442745                    
    443 class Person extends ADOdb_Active_Record{} 
    444 $person = new Person(); 
     746class person extends ADOdb_Active_Record{} 
     747$person = new person(); 
    445748 
    446749echo "&lt;p>Output of getAttributeNames: "; 
     
    461764 */ 
    462765 
    463 $person = new Person(); 
    464 $person->nameFirst = 'Andi'; 
    465 $person->nameLast  = 'Gutmans'; 
     766$person = new person(); 
     767$person->name_first = 'Andi'; 
     768$person->name_last  = 'Gutmans'; 
    466769$person->save(); // this save() will fail on INSERT as favorite_color is a must fill... 
    467770 
    468771 
    469 $person = new Person(); 
     772$person = new person(); 
    470773$person->name_first     = 'Andi'; 
    471774$person->name_last      = 'Gutmans'; 
     
    478781$person->save(); // this save() will perform an UPDATE 
    479782 
    480 $person = new Person(); 
     783$person = new person(); 
    481784$person->name_first     = 'John'; 
    482785$person->name_last      = 'Lim'; 
     
    485788 
    486789// load record where id=2 into a new ADOdb_Active_Record 
    487 $person2 = new Person(); 
     790$person2 = new person(); 
    488791$person2->Load('id=2'); 
    489792var_dump($person2); 
    490793 
    491794// retrieve an array of records 
    492 $activeArr = $db->GetActiveRecordsClass($class = "Person",$table = "persons","id=".$db->Param(0),array(2)); 
    493 $person2 =& $activeArr[0]; 
     795$activeArr = $db->GetActiveRecordsClass($class = "person",$table = "persons","id=".$db->Param(0),array(2)); 
     796$person2 = $activeArr[0]; 
    494797echo "&lt;p>Name first (should be John): ",$person->name_first, "&lt;br>Class = ",get_class($person2);   
    495798</pre> 
    496799 
     800 
     801 
     802<a name=recordx> 
     803<h2>Active Record eXtended</h2> 
     804<p>This is the original one-to-many Active Record implementation submitted by 
     805Chris Ravenscroft  (chris#voilaweb.com). The reason why we are offering both versions is that the Extended version 
     806is more powerful but more complex. My personal preference is to keep it simpler, but your view may vary.  
     807<p>To use, just include adodb-active-recordx.inc.php instead of adodb-active-record.inc.php. 
     808<p>It provides a new function called Find() that is quite intuitive to use as shown in the example below. It also supports loading all relationships using a single query (using joins). 
     809<pre> 
     810&lt;?php 
     811        function ar_assert($obj, $cond) 
     812        { 
     813                global $err_count; 
     814                $res = var_export($obj, true); 
     815                return (strpos($res, $cond)); 
     816        } 
     817 
     818        include_once('../adodb.inc.php'); 
     819        include_once('../adodb-active-recordx.inc.php'); 
     820         
     821 
     822        $db = NewADOConnection('mysql://root@localhost/northwind'); 
     823        $db->debug=0; 
     824        ADOdb_Active_Record::SetDatabaseAdapter($db); 
     825        echo "&lt;pre>\n"; 
     826        echo "\n\n---------------------------------------------------------------------------\n"; 
     827        echo "Preparing database using SQL queries (creating 'people', 'children')\n"; 
     828 
     829        $db->Execute("DROP TABLE `people`"); 
     830        $db->Execute("DROP TABLE `children`"); 
     831 
     832        $db->Execute("CREATE TABLE `people` ( 
     833                        `id` int(10) unsigned NOT NULL auto_increment, 
     834                        `name_first` varchar(100) NOT NULL default '', 
     835                        `name_last` varchar(100) NOT NULL default '', 
     836                        `favorite_color` varchar(100) NOT NULL default '', 
     837                        PRIMARY KEY  (`id`) 
     838                    ) ENGINE=MyISAM; 
     839                   "); 
     840        $db->Execute("CREATE TABLE `children` ( 
     841                        `id` int(10) unsigned NOT NULL auto_increment, 
     842                                        `person_id` int(10) unsigned NOT NULL, 
     843                        `name_first` varchar(100) NOT NULL default '', 
     844                        `name_last` varchar(100) NOT NULL default '', 
     845                        `favorite_pet` varchar(100) NOT NULL default '', 
     846                        PRIMARY KEY  (`id`) 
     847                    ) ENGINE=MyISAM; 
     848                   "); 
     849                            
     850         
     851        $db->Execute("insert into children (person_id,name_first,name_last,favorite_pet) values (1,'Jill','Lim','tortoise')"); 
     852        $db->Execute("insert into children (person_id,name_first,name_last) values (1,'Joan','Lim')"); 
     853        $db->Execute("insert into children (person_id,name_first,name_last) values (1,'JAMIE','Lim')"); 
     854                            
     855        // This class _implicitely_ relies on the 'people' table (pluralized form of 'person') 
     856        class Person extends ADOdb_Active_Record 
     857        { 
     858                function __construct() 
     859                { 
     860                        parent::__construct(); 
     861                        $this->hasMany('children'); 
     862                } 
     863        } 
     864        // This class _implicitely_ relies on the 'children' table 
     865        class Child extends ADOdb_Active_Record 
     866        { 
     867                function __construct() 
     868                { 
     869                        parent::__construct(); 
     870                        $this->belongsTo('person'); 
     871                } 
     872        } 
     873        // This class _explicitely_ relies on the 'children' table and shares its metadata with Child 
     874        class Kid extends ADOdb_Active_Record 
     875        { 
     876                function __construct() 
     877                { 
     878                        parent::__construct('children'); 
     879                        $this->belongsTo('person'); 
     880                } 
     881        } 
     882        // This class _explicitely_ relies on the 'children' table but does not share its metadata 
     883        class Rugrat extends ADOdb_Active_Record 
     884        { 
     885                function __construct() 
     886                { 
     887                        parent::__construct('children', false, false, array('new' => true)); 
     888                } 
     889        } 
     890         
     891        echo "Inserting person in 'people' table ('John Lim, he likes lavender')\n"; 
     892        echo "---------------------------------------------------------------------------\n"; 
     893        $person = new Person(); 
     894        $person->name_first     = 'John'; 
     895        $person->name_last      = 'Lim'; 
     896        $person->favorite_color = 'lavender'; 
     897        $person->save(); // this save will perform an INSERT successfully 
     898 
     899        $err_count = 0; 
     900 
     901        echo "\n\n---------------------------------------------------------------------------\n"; 
     902        echo "person->Find('id=1') [Lazy Method]\n"; 
     903        echo "person is loaded but its children will be loaded on-demand later on\n"; 
     904        echo "---------------------------------------------------------------------------\n"; 
     905        $person5 = new Person(); 
     906        $people5 = $person5->Find('id=1'); 
     907        echo (ar_assert($people5, "'name_first' => 'John'")) ? "[OK] Found John\n" : "[!!] Find failed\n"; 
     908        echo (ar_assert($people5, "'favorite_pet' => 'tortoise'")) ? "[!!] Found relation when I shouldn't\n" : "[OK] No relation yet\n"; 
     909        foreach($people5 as $person) 
     910        { 
     911                foreach($person->children as $child) 
     912                { 
     913                        if($child->name_first); 
     914                } 
     915        } 
     916        echo (ar_assert($people5, "'favorite_pet' => 'tortoise'")) ? "[OK] Found relation: child\n" : "[!!] Missing relation: child\n"; 
     917 
     918        echo "\n\n---------------------------------------------------------------------------\n"; 
     919        echo "person->Find('id=1' ... ADODB_WORK_AR) [Worker Method]\n"; 
     920        echo "person is loaded, and so are its children\n"; 
     921        echo "---------------------------------------------------------------------------\n"; 
     922        $person6 = new Person(); 
     923        $people6 = $person6->Find('id=1', false, false, array('loading' => ADODB_WORK_AR)); 
     924        echo (ar_assert($people6, "'name_first' => 'John'")) ? "[OK] Found John\n" : "[!!] Find failed\n"; 
     925        echo (ar_assert($people6, "'favorite_pet' => 'tortoise'")) ? "[OK] Found relation: child\n" : "[!!] Missing relation: child\n"; 
     926 
     927        echo "\n\n---------------------------------------------------------------------------\n"; 
     928        echo "person->Find('id=1' ... ADODB_JOIN_AR) [Join Method]\n"; 
     929        echo "person and its children are loaded using a single query\n"; 
     930        echo "---------------------------------------------------------------------------\n"; 
     931        $person7 = new Person(); 
     932        // When I specifically ask for a join, I have to specify which table id I am looking up 
     933        // otherwise the SQL parser will wonder which table's id that would be. 
     934        $people7 = $person7->Find('people.id=1', false, false, array('loading' => ADODB_JOIN_AR)); 
     935        echo (ar_assert($people7, "'name_first' => 'John'")) ? "[OK] Found John\n" : "[!!] Find failed\n"; 
     936        echo (ar_assert($people7, "'favorite_pet' => 'tortoise'")) ? "[OK] Found relation: child\n" : "[!!] Missing relation: child\n"; 
     937         
     938        echo "\n\n---------------------------------------------------------------------------\n"; 
     939        echo "person->Load('people.id=1') [Join Method]\n"; 
     940        echo "Load() always uses the join method since it returns only one row\n"; 
     941        echo "---------------------------------------------------------------------------\n"; 
     942        $person2 = new Person(); 
     943        // Under the hood, Load(), since it returns only one row, always perform a join 
     944        // Therefore we need to clarify which id we are talking about. 
     945        $person2->Load('people.id=1'); 
     946        echo (ar_assert($person2, "'name_first' => 'John'")) ? "[OK] Found John\n" : "[!!] Find failed\n"; 
     947        echo (ar_assert($person2, "'favorite_pet' => 'tortoise'")) ? "[OK] Found relation: child\n" : "[!!] Missing relation: child\n"; 
     948 
     949        echo "\n\n---------------------------------------------------------------------------\n"; 
     950        echo "child->Load('children.id=1') [Join Method]\n"; 
     951        echo "We are now loading from the 'children' table, not from 'people'\n"; 
     952        echo "---------------------------------------------------------------------------\n"; 
     953        $ch = new Child(); 
     954        $ch->Load('children.id=1'); 
     955        echo (ar_assert($ch, "'name_first' => 'Jill'")) ? "[OK] Found Jill\n" : "[!!] Find failed\n"; 
     956        echo (ar_assert($ch, "'favorite_color' => 'lavender'")) ? "[OK] Found relation: person\n" : "[!!] Missing relation: person\n"; 
     957 
     958        echo "\n\n---------------------------------------------------------------------------\n"; 
     959        echo "child->Find('children.id=1' ... ADODB_WORK_AR) [Worker Method]\n"; 
     960        echo "---------------------------------------------------------------------------\n"; 
     961        $ch2 = new Child(); 
     962        $ach2 = $ch2->Find('id=1', false, false, array('loading' => ADODB_WORK_AR)); 
     963        echo (ar_assert($ach2, "'name_first' => 'Jill'")) ? "[OK] Found Jill\n" : "[!!] Find failed\n"; 
     964        echo (ar_assert($ach2, "'favorite_color' => 'lavender'")) ? "[OK] Found relation: person\n" : "[!!] Missing relation: person\n"; 
     965 
     966        echo "\n\n---------------------------------------------------------------------------\n"; 
     967        echo "kid->Find('children.id=1' ... ADODB_WORK_AR) [Worker Method]\n"; 
     968        echo "Where we see that kid shares relationships with child because they are stored\n"; 
     969        echo "in the common table's metadata structure.\n"; 
     970        echo "---------------------------------------------------------------------------\n"; 
     971        $ch3 = new Kid('children'); 
     972        $ach3 = $ch3->Find('children.id=1', false, false, array('loading' => ADODB_WORK_AR)); 
     973        echo (ar_assert($ach3, "'name_first' => 'Jill'")) ? "[OK] Found Jill\n" : "[!!] Find failed\n"; 
     974        echo (ar_assert($ach3, "'favorite_color' => 'lavender'")) ? "[OK] Found relation: person\n" : "[!!] Missing relation: person\n"; 
     975 
     976        echo "\n\n---------------------------------------------------------------------------\n"; 
     977        echo "kid->Find('children.id=1' ... ADODB_LAZY_AR) [Lazy Method]\n"; 
     978        echo "Of course, lazy loading also retrieve medata information...\n"; 
     979        echo "---------------------------------------------------------------------------\n"; 
     980        $ch32 = new Kid('children'); 
     981        $ach32 = $ch32->Find('children.id=1', false, false, array('loading' => ADODB_LAZY_AR)); 
     982        echo (ar_assert($ach32, "'name_first' => 'Jill'")) ? "[OK] Found Jill\n" : "[!!] Find failed\n"; 
     983        echo (ar_assert($ach32, "'favorite_color' => 'lavender'")) ? "[!!] Found relation when I shouldn't\n" : "[OK] No relation yet\n"; 
     984        foreach($ach32 as $akid) 
     985        { 
     986                if($akid->person); 
     987        } 
     988        echo (ar_assert($ach32, "'favorite_color' => 'lavender'")) ? "[OK] Found relation: person\n" : "[!!] Missing relation: person\n"; 
     989         
     990        echo "\n\n---------------------------------------------------------------------------\n"; 
     991        echo "rugrat->Find('children.id=1' ... ADODB_WORK_AR) [Worker Method]\n"; 
     992        echo "In rugrat's constructor it is specified that\nit must forget any existing relation\n"; 
     993        echo "---------------------------------------------------------------------------\n"; 
     994        $ch4 = new Rugrat('children'); 
     995        $ach4 = $ch4->Find('children.id=1', false, false, array('loading' => ADODB_WORK_AR)); 
     996        echo (ar_assert($ach4, "'name_first' => 'Jill'")) ? "[OK] Found Jill\n" : "[!!] Find failed\n"; 
     997        echo (ar_assert($ach4, "'favorite_color' => 'lavender'")) ? "[!!] Found relation when I shouldn't\n" : "[OK] No relation found\n"; 
     998 
     999        echo "\n\n---------------------------------------------------------------------------\n"; 
     1000        echo "kid->Find('children.id=1' ... ADODB_WORK_AR) [Worker Method]\n"; 
     1001        echo "Note how only rugrat forgot its relations - kid is fine.\n"; 
     1002        echo "---------------------------------------------------------------------------\n"; 
     1003        $ch5 = new Kid('children'); 
     1004        $ach5 = $ch5->Find('children.id=1', false, false, array('loading' => ADODB_WORK_AR)); 
     1005        echo (ar_assert($ach5, "'name_first' => 'Jill'")) ? "[OK] Found Jill\n" : "[!!] Find failed\n"; 
     1006        echo (ar_assert($ach5, "'favorite_color' => 'lavender'")) ? "[OK] I did not forget relation: person\n" : "[!!] I should not have forgotten relation: person\n"; 
     1007         
     1008        echo "\n\n---------------------------------------------------------------------------\n"; 
     1009        echo "rugrat->Find('children.id=1' ... ADODB_WORK_AR) [Worker Method]\n"; 
     1010        echo "---------------------------------------------------------------------------\n"; 
     1011        $ch6 = new Rugrat('children'); 
     1012        $ch6s = $ch6->Find('children.id=1', false, false, array('loading' => ADODB_WORK_AR)); 
     1013        $ach6 = $ch6s[0]; 
     1014        echo (ar_assert($ach6, "'name_first' => 'Jill'")) ? "[OK] Found Jill\n" : "[!!] Find failed\n"; 
     1015        echo (ar_assert($ach6, "'favorite_color' => 'lavender'")) ? "[!!] Found relation when I shouldn't\n" : "[OK] No relation yet\n"; 
     1016        echo "\nLoading relations:\n"; 
     1017        $ach6->belongsTo('person'); 
     1018        $ach6->LoadRelations('person', 'order by id', 0, 2); 
     1019        echo (ar_assert($ach6, "'favorite_color' => 'lavender'")) ? "[OK] Found relation: person\n" : "[!!] Missing relation: person\n"; 
     1020 
     1021        echo "\n\n---------------------------------------------------------------------------\n"; 
     1022        echo "Test suite complete.\n"; 
     1023        echo "---------------------------------------------------------------------------\n"; 
     1024?> 
     1025</pre> 
    4971026 <h3>Todo (Code Contributions welcome)</h3> 
    4981027 <p>Check _original and current field values before update, only update changes. Also if the primary key value is changed, then on update, we should save and use the original primary key values in the WHERE clause! 
    499  <p>Handle 1-to-many relationships. 
     1028 
    5001029 <p>PHP5 specific:  Make GetActiveRecords*() return an Iterator. 
    5011030 <p>PHP5 specific: Change PHP5 implementation of Active Record to use __get() and __set() for better performance. 
    5021031 
    5031032<h3> Change Log</h3> 
     1033<p>0.93 
     1034<p>You can force column names to be quoted in INSERT and UPDATE statements, typically because you are using reserved words as column names by setting 
     1035ADODB_Active_Record::$_quoteNames = true; 
     1036 
     1037<p>0.92 
     1038<p>Fixed some issues with incompatible fetch modes (ADODB_FETCH_ASSOC) causing problems in UpdateActiveTable. 
     1039<p>Added support for functions that support predefining one-to-many relationships:<br>  
     1040&nbsp; <i>ClassHasMany ClassBelongsTo TableHasMany TableBelongsTo TableKeyHasMany TableKeyBelongsTo</i>. <br> 
     1041<p>You can also define your child/parent class in these functions, instead of the default ADODB_Active_Record. 
     1042 
     1043<P>0.91 
     1044<p>HasMany hardcoded primary key field name to "id". Fixed. 
     1045 
     1046<p>0.90 
     1047<p>Support for belongsTo and hasMany. Thanks to Chris Ravenscroft (chris#voilaweb.com). 
     1048<p>Added LoadRelations(). 
     1049 
     1050<p>0.08 
     1051Added support for assoc arrays in Set(). 
     1052 
    5041053<p>0.07 
    5051054<p>$ADODB_ASSOC_CASE=2 did not work properly. Fixed. 
Note: See TracChangeset for help on using the changeset viewer.