Home » Database » DB_DataObject » Bug #7157
__autoload not called for getLink()
Details
| Submitted | 2006-03-19 00:38 UTC |
|---|---|
| From | cuppett at gmail dot com |
| Assigned | alan_k |
| Status | Closed |
| Package | DB_DataObject |
| PHP Version | 5.1.2 |
| OS | Linux |
| Roadmaps | (Not assigned) |
Comments
[2006-03-19 00:38 UTC] cuppett at gmail dot com
Description:
------------
If a custom __autoload function is provided in PHP 5.1.2 it appears to get called just fine by DB_DataObjects as long as the first reference to a particular class isn't happening inside of the ->getLink member function.
__autoload is correctly utilized when instantiating a new object; however, when instantiation is implicit (getLink) it is not called correctly.
Test script:
---------------
In the following code:
$session = $request->getSession();
if ($ticket = $user->getLink('id', 'Ticket', 'submitter'))
{...}
if $user is another DB_DataObject that has already been retrieved (via find) he will properly autoload. However, Ticket will fail to autoload.
In order to make this work, prior to the conditional it is necessary to add something arbitrary such as:
$ticket = new DataObjects_Ticket;
And then just override it in the conditional with $user->getLink(...).
Expected result:
----------------
You would expect no problems from using the API in this way. If factory fails, custom __autoload should be last resort and be called per language spec.
Actual result:
--------------
The following is what is observed:
DataObjects_User: fetchrow: users DONE
DataObjects_User: find: DONE
DataObjects_User: ERROR: factory could not find class from Ticket
DataObjects_User: ERROR: getLink:Could not find class for row id, table Ticket
with some simple echo commands in the custom __autoload function it is easy to observe that the fetch or new() calls trigger __autoload but that getLink() does not.
[2006-03-20 19:31 UTC] cuppett at gmail dot com
Should I use 5.1.x snapshot or 6.0-dev?
[2006-03-20 23:34 UTC] cuppett at gmail dot com
Have tried this with latest 5.1.x snapshot:
php5.1-200603202130
with same results.
[2006-03-21 17:57 UTC] cuppett at gmail dot com
Have created reproducible example. Documenting it here and then will attempt to find where to open a PHP bug.
Recreated under:
PHP 5.1.3RC2-dev (cli) (built: Mar 21 2006 10:50:11)
5.1-200603211530
________START DATABASE________
DROP TABLE IF EXISTS `users`;
CREATE TABLE `users` (
`id` bigint(20) NOT NULL auto_increment,
`username` varchar(15) NOT NULL default '',
`password` varchar(15) NOT NULL default '',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
--
-- Table structure for table `tickets`
--
DROP TABLE IF EXISTS `tickets`;
CREATE TABLE `tickets` (
`id` bigint(20) NOT NULL auto_increment,
`subject` varchar(25) NOT NULL default '',
`submitter` bigint(20) default NULL,
PRIMARY KEY (`id`),
KEY `submitter` (`submitter`),
CONSTRAINT `tickets_ibfk_1` FOREIGN KEY (`submitter`) REFERENCES `users` (`id`) ON DELETE SET NULL ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO `users` VALUES (1,'cuppett','t3st');
INSERT INTO `tickets` VALUES (1,'Test tick 1',1),(2,'Test tick 2',1),(3,'Test tick 3',1);
________END DATABASE________
____________START OF INDEX.PHP______________
<?php
require("DB.php");
define('DB_DATAOBJECT_NO_OVERLOAD',0);
$options = &PEAR::getStaticProperty('DB_DataObject','options');
$options = array(
'database' => 'mysql://testuser:t3st@localhost/test',
'require_prefix' => 'includes/',
'class_prefix' => 'DataObjects_',
'quote_identifiers' => '1'
);
require("DB/DataObject.php");
DB_DataObject::debugLevel(5); // Turns on full debugging of SQL generated and results.
?>
<HTML>
<HEAD>
<TITLE>__autoload Bug</TITLE>
</HEAD>
<BODY>
<?php
$user = new DataObjects_User;
$user->username = cuppett;
if ($user->find(true)) {
if ($ticket = $user->getLink("id", "Ticket", "submitter"))
{
echo "Found everything just fine.";
}
}
?>
</BODY>
<?php
function __autoload($className)
{
echo "Trying to find class: " . $className . "\n<br>";
$className = strtolower($className);
if (file_exists("includes/" . $className . ".php"))
{
echo "Found in includes.\n<br>";
include("includes/" . $className . ".php");
}
}
?>
____________END OF INDEX.PHP______________
____________START OF DATAOBJECTS_USER.PHP______________
<?php
class DataObjects_User extends DB_DataObject {
var $__table='users';
var $id;
var $username;
var $password;
// Schema definition for the object
/* Static get */
function staticGet($k,$v=NULL) { return DB_DataObject::staticGet('DataObjects_User',$k,$v); }
// now define your table structure.
// key is column name, value is type
function table() {
return array(
'id' => DB_DATAOBJECT_INT,
'username' => DB_DATAOBJECT_STR,
'password' => DB_DATAOBJECT_STR
);
}
// now define the keys.
function keys() {
return array('id');
}
}
?>
____________END OF DATAOBJECTS_USER.PHP______________
____________START OF DATAOBJECTS_TICKET.PHP______________
<?php
class DataObjects_Ticket extends DB_DataObject {
var $__table='tickets';
var $id;
var $submitter;
var $subject;
// Schema definition for the object
/* Static get */
function staticGet($k,$v=NULL) { return DB_DataObject::staticGet('DataObjects_Ticket',$k,$v); }
// now define your table structure.
// key is column name, value is type
function table() {
return array(
'id' => DB_DATAOBJECT_INT,
'submitter' => DB_DATAOBJECT_INT,
'subject' => DB_DATAOBJECT_STR
);
}
// now define the keys.
function keys() {
return array('id');
}
}
?>
____________END OF DATAOBJECTS_TICKET.PHP______________
[2006-03-21 18:00 UTC] cuppett at gmail dot com
Output from the sample code:
Trying to find class: DataObjects_User
Found in includes.
DataObjects_User: find: 1
DataObjects_User: CONNECT: Checking for database database_ in options
DataObjects_User: CONNECT: NEW CONNECTION
DataObjects_User: CONNECT: mysql://testuser:t3st@localhost/test e99174a55dfff52a26d46fb4e606d082
DataObjects_User: CONNECT: a:1:{s:32:"e99174a55dfff52a26d46fb4e606d082";O:8:"DB_mysql":8:{s:10:"autocommit";b:1;s:8:"dbsyntax";s:5:"mysql";s:3:"dsn";a:9:{s:7:"phptype";s:5:"mysql";s:8:"dbsyntax";s:5:"mysql";s:8:"username";s:8:"testuser";s:8:"password";s:4:"t3st";s:8:"protocol";s:3:"tcp";s:8:"hostspec";s:9:"localhost";s:4:"port";b:0;s:6:"socket";b:0;s:8:"database";s:4:"test";}s:8:"features";a:7:{s:5:"limit";s:5:"alter";s:8:"new_link";s:5:"4.2.0";s:7:"numrows";b:1;s:8:"pconnect";b:1;s:7:"prepare";b:0;s:3:"ssl";b:0;s:12:"transactions";b:1;}s:9:"fetchmode";i:1;s:22:"fetchmode_object_class";s:8:"stdClass";s:7:"options";a:8:{s:16:"result_buffering";i:500;s:10:"persistent";b:0;s:3:"ssl";b:0;s:5:"debug";i:0;s:14:"seqname_format";s:6:"%s_seq";s:8:"autofree";b:0;s:11:"portability";i:0;s:8:"optimize";s:11:"performance";}s:13:"was_connected";b:1;}}
DataObjects_User: QUERY: SELECT *
FROM `users`
WHERE ( `users`.`username` = 'cuppett' )
DataObjects_User: query: QUERY DONE IN 0.00091886520385742 seconds
DataObjects_User: RESULT: O:9:"DB_result":11:{s:8:"autofree";b:0;s:3:"dbh";O:8:"DB_mysql":8:{s:10:"autocommit";b:1;s:8:"dbsyntax";s:5:"mysql";s:3:"dsn";a:9:{s:7:"phptype";s:5:"mysql";s:8:"dbsyntax";s:5:"mysql";s:8:"username";s:8:"testuser";s:8:"password";s:4:"t3st";s:8:"protocol";s:3:"tcp";s:8:"hostspec";s:9:"localhost";s:4:"port";b:0;s:6:"socket";b:0;s:8:"database";s:4:"test";}s:8:"features";a:7:{s:5:"limit";s:5:"alter";s:8:"new_link";s:5:"4.2.0";s:7:"numrows";b:1;s:8:"pconnect";b:1;s:7:"prepare";b:0;s:3:"ssl";b:0;s:12:"transactions";b:1;}s:9:"fetchmode";i:1;s:22:"fetchmode_object_class";s:8:"stdClass";s:7:"options";a:8:{s:16:"result_buffering";i:500;s:10:"persistent";b:0;s:3:"ssl";b:0;s:5:"debug";i:0;s:14:"seqname_format";s:6:"%s_seq";s:8:"autofree";b:0;s:11:"portability";i:0;s:8:"optimize";s:11:"performance";}s:13:"was_connected";b:1;}s:9:"fetchmode";i:1;s:22:"fetchmode_object_class";s:8:"stdClass";s:11:"limit_count";N;s:10:"limit_from";N;s:10:"parameters";a:0:{}s:5:"query";s:79:"SELECT *
FROM `users`
WHERE ( `users`.`username` = 'cuppett' )
";s:6:"result";i:0;s:11:"row_counter";N;s:9:"statement";N;}
DataObjects_User: find: CHECK autofetchd 1
DataObjects_User: find: ABOUT TO AUTOFETCH
DataObjects_User: FETCH: a:3:{s:2:"id";s:1:"1";s:8:"username";s:7:"cuppett";s:8:"password";s:4:"t3st";}
DataObjects_User: fetchrow LINE: id = 1
DataObjects_User: fetchrow LINE: username = cuppett
DataObjects_User: fetchrow LINE: password = t3st
DataObjects_User: fetchrow: users DONE
DataObjects_User: find: DONE
DataObjects_User: ERROR: factory could not find class from Ticket
DataObjects_User: ERROR: getLink:Could not find class for row id, table Ticket
[2006-03-23 13:38 UTC] cuppett at gmail dot com
I would recommend a change that factory fall back on attempting to utilize the "new" call as a last resort such that __autoload behavior can take place; however, the changes recommended worked out for me. I really appreciate all the help and I hope that this bug proves to be a good use case user error example. Am closing this bug.
Here was the updated index.php:
<?php
require("DB.php");
define('DB_DATAOBJECT_NO_OVERLOAD',0);
$options = &PEAR::getStaticProperty('DB_DataObject','options');
$options = array(
'database' => 'mysql://testuser:t3st@localhost/test',
'require_prefix' => 'includes/',
'class_prefix' => 'DataObjects_',
'class_location' => dirname(__FILE__).'/includes/DataObjects_%s.php',
'quote_identifiers' => '1'
);
require("DB/DataObject.php");
DB_DataObject::debugLevel(5); // Turns on full debugging of SQL generated and results.
?>
<HTML>
<HEAD>
<TITLE>__autoload Bug</TITLE>
</HEAD>
<BODY>
<?php
$user = DB_DataObject::factory("User");
$user->username = cuppett;
if ($user->find(true)) {
if ($ticket = $user->getLink("id", "Ticket", "submitter"))
{
echo "Found everything just fine.";
}
}
?>
</BODY>
<?php
function __autoload($className)
{
echo "Trying to find class: " . $className . "\n<br>";
$className = strtolower($className);
if (file_exists("includes/" . $className . ".php"))
{
echo "Found in includes.\n<br>";
include("includes/" . $className . ".php");
}
}
?>