PEAR is archived and read-only

This mirror preserves historical PEAR package releases and metadata so existing references remain available.

Home » Database » DB_DataObject » Bug #3256

Allow custom file and class naming conventions

Details

Request #3256Allow custom file and class naming conventions
Submitted2005-01-20 23:46 UTC
Fromdb_dataobjects-bugs-2005 at ryandesign dot com
StatusSuspended
PackageDB_DataObject
PHP VersionIrrelevant
OSIrrelevant
Roadmaps(Not assigned)

Comments

[2005-01-20 23:46 UTC] db_dataobjects-bugs-2005 at ryandesign dot com

Description:
------------
There is code in DB_DataObjects which computes the name to
be used for each data object class and its PHP file. In
Generator.php it looks like this:

$this->classname = $class_prefix.preg_replace('/[^A-Z0-9]/
i','_',ucfirst($this->table));
$i = '';
$outfilename = "{$base}/".preg_replace('/[^A-Z0-9]/
i','_',ucfirst($this->table)).".php";

Code like this is also duplicated in other places in
DB_DataObjects.

I would like to see these preg_replace()s moved out into
new methods, like computeClassName($table) and
computeFileName($table), so that I could override these in
a child class to implement different behavior.

The reason for this is that I do not subscribe to the PEAR
notion that the first character of a class name should be
uppercase, and do not want this naming convention for
files in my project.

Furthermore all my table names begin with a version of my
project's name, followed by two underscores. This practice
is recommended by phpMyAdmin and has several advantages.
But I would like to dispense with these prefixes when
dealing with the data objects within my project.

The numerous places within the DB_DataObjects code where
changes would need to be made currently make it
impractical for me to implement differing behavior without
having to copy large sections of the DB_DataObjects code,
which is undesirable from a maintenance standpoint as new
versions of DB_DataObjects are released. By abstracting
these tasks into separate methods you would enable me to
achieve my desired result in the most effective way.

See also bugs 3013 and 2740 for similar requests.
Implementing the above suggestion may take care of those
users' needs as well.

I am using DB_DataObjects 1.7.2 with PHP 5.0.3, Apache
1.3.33 and Mac OS X 10.3.7.

[2005-05-14 03:07 UTC] jrhernandez05 at gmail dot com

I'm currently facing the same issue as the original poster, in which all the tables in my database have a prefix (e.g. T5010_ARTICLES) which I do not want in my class name (I just want an "Articles" class).

The problem with having an overridable method such as "className" is that it won't be used in most cases. The reason is that the DataObjects are created through the "factory" method, which is static. Other packages such as DB_DataObject_FormBuilder (which I also use) instantiate objects through this method.

Hence, an overridable method is not the solution. What I propose is having another config option, such as "xml_config_file", that when specified would instruct the DB_DataObject to get the settings from this XML file. This XML file would contain the following:

- Table to class name and file name mappings
- Column name mappings (would map a column name to a property name)
- Link information (no separate db.links.ini file)

I will be more than glad to provide this patch, but having just seen the DBDO PECL package (which looks very good, BTW), it would not seem reasonable to provide this functionality if DBDO, which will replace DB_DataObject, won't have something similar. I think DBDO should also have this feature, since all references to a table/column name will be in just one file, and abstracted elsewhere. If it could/will be included in DBDO, then I will start working on it...

[2005-05-14 21:35 UTC] jrhernandez05 at gmail dot com

Actually, I wasn't considering the generator portion, although the generator can also use this XML approach. I am primarily concerned on how the DataObject itself gets its database structure info. There could be an additional setting named "xml_config_file", or something to that effect, and that file would have the database structure information (it would consolidate the information for the "table()", "keys()", "sequenceKey()", and "links()" methods.

Below is an example of how the XML file could look like. Before viewing it, keep in mind that where I work we have a naming convention of TXXXX_NAME for tables and CXXXX_NAME for columns.

<database-structure>
<table name="t1001_customers" id-column-names="c1001_customer_id" sequence-key="c1001_customer_id,false,s1001_customer_id" class-name="Customer">
<column name="c1001_customer_id" data-type="integer" nullable="false" property-name="ID" />
<column name="c1001_name" data-type="string" nullable="false" property-name="name" />
<column name="c1001_phone" data-type="string" nullable="true" property-name="phone" />
<column name="c1002_state_id" data-type="integer" nullable="true" property-name="stateID" />

<link property-name="state" column-name="c1002_state_id" table-name="t1002_states" table-column-name="c1002_state_id" />
</table>

<table name="t1002_states" id-column-names="c1002_state_id" sequence-key="c1002_state_id,false,c1002_state_id" class-name="State">
<column name="c1002_state_id" data-type="integer" nullable="false" property-name="ID" />
<column name="c1002_name" data-type="string" nullable="false" property-name="name" />
<column name="c1002_abbreviation" data-type="string" nullable="false" property-name="abbreviation" />
</table>
</database-structure>

Some notes on the above:

1) id-column-names maps is used by "keys()".
2) sequence-key is used by "sequenceKey()".
3) The class-name attribute contains the name of the class to use. If not specified, then the table name will be used.
4) The data-type attribute contains a primitive PHP type. It might be useful if it could also contain the name of a class (if it's not a primitive type, then it would be assumed that it's a class and the property would be initialized as $this->$p = new $dataType($columnValue)).
5) Each "link" tag under a table would specify the links under each table. In the example above, there would be an additional property for the Customer class named "state", which would be an instance of the State class, which has three other properties: "ID", "name", and "abbreviation".

Let me know what you think and if you have any suggestions.

[2005-05-14 21:41 UTC] jrhernandez05 at gmail dot com

The XML code above looks cluttered due to wrapping. Hope the following is a bit clearer to read:

<database-structure>
<table name="t1001_customers"
id-column-names="c1001_customer_id"
sequence-key="c1001_customer_id,false,s1001_customer_id"
class-name="Customer">

<column name="c1001_customer_id"
data-type="integer"
nullable="false"
property-name="ID" />
<column name="c1001_name"
data-type="string"
nullable="false"
property-name="name" />
<column name="c1001_phone"
data-type="string"
nullable="true"
property-name="phone" />
<column name="c1002_state_id"
data-type="integer"
nullable="true"
property-name="stateID" />

<link property-name="state"
column-name="c1002_state_id"
table-name="t1002_states"
table-column-name="c1002_state_id" />
</table>

<table name="t1002_states"
id-column-names="c1002_state_id"
sequence-key="c1002_state_id,false,c1002_state_id"
class-name="State">

<column name="c1002_state_id"
data-type="integer"
nullable="false"
property-name="ID" />
<column name="c1002_name"
data-type="string"
nullable="false"
property-name="name" />
<column name="c1002_abbreviation"
data-type="string"
nullable="false"
property-name="abbreviation" />
</table>
</database-structure>

[2005-05-17 23:16 UTC] db_dataobjects-bugs-2005 at ryandesign dot com

I personally wouldn't want to have to create and
maintain such an XML file. My table names follow a
convention, always. I'd much rather define a short PHP
function to map those table names to the corresponding
class and file names than have to maintain an
umpteen-line XML file over the lifetime of my
application.

It seems to me like I should be able to do it like this:

require_once 'DB/DataObject.php';
DB_DataObject::setClassNamer(create_function('$x',
'return strtolower(substr($x, strpos($x, "__")+2));'
));
DB_DataObject::setFileNamer(create_function('$x',
'return strtolower(substr($x, strpos($x, "__")+2)) '
. '. ".class";'));

This would implement the naming strategy I want, which
is to say that I have a table called
"myDatabase__myTable" and I want the class to be
"mytable" and the PHP file to be "mytable.class.php".

Then, after that initial setup, any PHP file, any
3rd-party library like DB_DataObjects_FormBuilder, can
call the factory method or whatever, and internally,
DB_DataObject can call
DB_DataObject::getClassName($tableName) to get the class
name and DB_DataObject::getFileName($tableName) to get
the file name.

Here's how these four new functions might be implemented
in DB_DataObject:

class DB_DataObject {
function setClassNamer($function) {
global $_DB_DATAOBJECT;
$_DB_DATAOBJECT['classNamer'] = $function;
}
function setFileNamer($function) {
global $_DB_DATAOBJECT;
$_DB_DATAOBJECT['fileNamer'] = $function;
}
function getClassName($tableName) {
global $_DB_DATAOBJECT;
return $_DB_DATAOBJECT['classNamer']($tableName);
}
function getFileName($tableName) {
global $_DB_DATAOBJECT;
return $_DB_DATAOBJECT['fileNamer']($tableName)
. '.php';
}
}

Column names could be handled in a similar way.

I have no comment on how this could work in DBDO as I've
never worked with PECL.

[2005-05-18 03:21 UTC] jrhernandez05 at gmail dot com

From my experience, the XML approach is not cumbersome to maintain (our production J2EE server uses this same approach, and we've been using it for about 4 years now with no complaints). But I do see that with your approach, there would be less code to write. I would actually go further and have a class which implements the "namer" methods. The DB_DataObject class could use one standard namer class, DB_DataObject_Namer, and implement two static methods, "getNamer" and "setNamer". Users could extend the DB_DataObject_Namer class and override whichever namer methods they need. Here's an example:

DB_DATAOBJECT_NAMER
-------------------------
class DB_DataObject_Namer
{
function getClassName($tableName)
{
return $tableName;
}

function getFileName($tableName)
{
return $tableName . '.php';
}

function getPropertyName($tableName, $columnName)
{
return $columnName;
}

function getLinkPropertyName($table1, $column1, $table2, $column2)
{
return '_' . str_replace( '.', '_', $column1 );
}
};

MY_NAMER
--------
class MyNamer extends DB_DataObject_Namer
{
function getClassName($tableName)
{
return substr( $tableName, strpos( $tableName, '_'
) + 1 );
}

function getFileName($tableName)
{
// in this case, the class and file names are the same
return $this->getClassName( $tableName ) . '.php';
}

/* NOTE: By not overriding the other methods, the default behavior will be used. */
};

SAMPLE USAGE
------------

require_once( 'DB/DataObject.php' );
require_once( 'MyCompany/MyNamer.php' );

DB_DataObject::setNamer( new MyNamer() );

// use DB_DataObject as usual...

[2005-10-05 08:53 UTC] pearuser at yahoo dot com

FWIW:
simple patch to have control of filename prefix (ini option class_filename_prefix.

--- /usr/lib/php/DB/DataObject/Generator.php 2005-10-05 03:48:09.000000000 -0500
+++ Generator.php 2005-10-05 03:46:07.000000000 -0500
@@ -495,6 +495,7 @@
System::mkdir(array('-p',$base));
}
$class_prefix = $options['class_prefix'];
+ $class_filename_prefix = $options['class_filename_prefix'];
if ($extends = @$options['extends']) {
$this->_extends = $extends;
$this->_extendsFile = $options['extends_location'];
@@ -506,9 +507,9 @@
$i = '';

if (strpos($options['class_location'],'%s') !== false) {
- $outfilename = sprintf($options['class_location'], preg_replace('/[^A-Z0-9]/i','_',ucfirst($this->table)));
+ $outfilename = sprintf($options['class_location'], preg_replace('/[^A-Z0-9]/i','_',$class_filename_prefix.ucfirst($this->table)));
} else {
- $outfilename = "{$base}/".preg_replace('/[^A-Z0-9]/i','_',ucfirst($this->table)).".php";
+ $outfilename = "{$base}/".preg_replace('/[^A-Z0-9]/i','_',$class_filename_prefix.ucfirst($this->table)).".php";
}
$oldcontents = '';
if (file_exists($outfilename)) {