PX : code

SQL code to PHP Classes by Stephan Beal
Download this code


#!/usr/bin/perl
# Takes text from an SQL-style CREATE TABLE definition and makes
# a PHP class out of it.
# by Stephan, Feb '00
# stephan@wanderinghorse.net
# http://www.wanderinghorse.net
#
# Please read the instructions below before submitting any bugs or questions!
#
#####
# Usage: sql2php [codefilename] < CREATE_TABLE_FILE
#
# Output will be one PHP file for each table defined in the input stream,
# with a class definition, and get/set methods for every field in the table.
# The java file will be named Foo.java, where Foo is the name of your table,
# and it will be in the current directory. sql2php can handle sql code with
# more than one CREATE TABLE definition, as long as they are all well-formed -
# sql2php does NO error checking on the input at all, so if it sits there for 
# a long time without doing anything, it's probably caught in an endless loop 
# from a bug or invalid input.
#
# Pass it the name of a file as parameter 1 and it'll include the text of 
# that file as extra code, inserting it between the constructor and
# accessors. 
#
# This is written to accept output generated by "mysqldump -d"!!!
# I won't guaranty that it will work with hand-rolled SQL or code
# generated by other tools!!!
# I've tested it with the mysqldump which ships with MySQL 3.22.[2|3]x
# (Linux and Windows).
#
#####
# I get really screwed up intentation, but it's not a problem in
# this code. Many indentions come out short by one space on my machine, 
# for a reason I cannot see.
#
# What this DOES do:
#  - Creates a PHP file for each CREATE TABLE(...); block given to it,
#    complete with get/set methods and constructor skeleton for each field.
#  - Accepts output in the format generated by "mysqldump -d". No other format
#    has been tested, but should be okay as long as it's clean and it's closing
#    ");" is on a line of it's own (it will skip a field if that closing is on the
#    same line as a field). I've tested it with mysqldump 3.22.2x and 3.22.30.
#   
# What this DOES NOT do:
#  - Add any database-connection code. That is typically handle differently
#    by each developer, so I've left that out. You can use the "code file"
#    inclusion to help simulate this. I may add some limited variable expansion 
#    to the code inclusion so you can write generic skeletons and have some fields
#    replaces to match your object names. For now I use a sed script to do that.
#  - Any error checking on the input. If sql2php sits for a long time without
#    doing anything, it's probably caught in an endless loop caused  by a bug
#    or bad input. 
#
#
# Performance note:
# This is blazing fast, assuming you have the SQL code locally available. 
# On a db with 537 fields across 32 tables, it normally completes in less 
# then 0.4 seconds on a 400Mhz laptop woth 128MB RAM and a mid-speed,
# no-cache hard drive.
# That's using output directly from mysqldump, as in:
#    mysqldump -d myluckydatabase | sql2php
#
#
#
#####
# Possible future features:
# - Setting of default values, as set by DEFAULT in the CREATE TABLE code.
# - Special handling of PRIMARY KEY fields(???).
# - Db-related functions, which allow collection of Objects based on SQL code. I currently
#   do this with the include file (the 1st parameter sent to sql2php).
# - Add a getUpdateString() method to the output  code, which generates an "UPDATE foo SET...." 
#   for the object. This needs the PRIMARY KEY support, though, to be really useful.
#
#####
# LICENSE:
# sql2php is in the PUBLIC DOMAIN. You may do WHATEVER YOU WANT WITH IT,
# but it comes with NO WARRANTY WHATSOEVER, express or implied.
#
#####

BEGIN {
  $VERSION="0.1 (Feb 15th, 2000)";
  $DESC = "sql2php version $VERSION by Stephan Beal (stephan\@wanderinghorse.net)";
  $TBL_COUNT = 0;
  $FLD_COUNT = 0;
  print STDERR $DESC.".\n";
}
END {
  stderr( "Done! $TBL_COUNT tables and $FLD_COUNT fields processed!\n" );
}

# Get custom code from user...
@CUSTOM;
if ( $ARGV[0] ) {
  open( EXTRA, "<$ARGV[0]" );
  if ( ! EXTRA ) {
    print STDERR "\bCould not open $ARGV[0] for reading!".
      "Extra code NOT INCLUDED!\n\n";
  }
  @CUSTOM = <EXTRA>;
}

@LINES=<STDIN>;
$size = @LINES;
$tbl = "";
@ACC;
@CODE;
$T="\t";
@METHODS;
@ATTRIBUTES; # code which will go in the constructor.

# Loop through input...
for( $i = 0; $i < $size; $i++ ) {
  $l = $LINES[$i];
  next unless ( $l =~ /CREATE TABLE (\w*)/ );
#    print "1=$1\t2=$2\t3=$3\n";
    $tbl = $1;
    stderr("Working on class $tbl...\n");
      $l = $LINES[$i++];
    while( $l !~ /\);/ ) {
 #     print $l;
      if ( $l =~ /\s*(\w+)\s+(.+),/ ) {
     my $fld=$1;
    accessor( $fld );
      }
      $l = $LINES[$i++];
    }

#    if ( $ENV{JAVA_PACKAGE} =~ /\w/ ) {
#      $package = "package ".$ENV{JAVA_PACKAGE}.";\n";
#    }
#    else { $package = "";}
  $outfile = "$tbl.php";
    open( PHP, ">$outfile" ) or die "Cannot open $outfile for output!!!\n";
    $time=localtime;
    print PHP << "EOC";
<?
############################################################
# Generated by...
# $DESC.
# on $time

class $tbl
{
@CODE
#############################################################
# Constructor.
# Optionally pass it an array with the attributes (pulled from mysql_fetch_row(), for example).
# The attributes each correspond to one of the variables with a get/set functions. e.g. the attribute
# for getFoo() is 'Foo' or 'foo' (you'll need to look at the variables section at the top of
# this class to be sure).
    function $tbl( \$attributes=false )
    {
        if( \$attributes != false ) 
    {
@ATTRIBUTES
    }
    }

@CUSTOM

@METHODS

} // end class $tbl

?>
EOC
  close PHP;
  stderr( "\t$outfile created.\n" );
    @CODE="";
    @METHODS="";
$TBL_COUNT++;
} # end for ($i...<$size...)


############################################################
# Subroutines go down here...
############################################################

########################################
# Adds a field to the CODE array and creates get/set methods
# for the field.
sub accessor() {
  my $fld = shift;
  ++$FLD_COUNT;
  code( "\tvar \t\$$fld;" );
  $uc = $fld;
  $uc =~ s/^(\w)/uc($1)/e;

  # GET...
  $line = "########################################";
  push( @METHODS, "$line\n# Get the value of $fld.\n" );
  push( @METHODS,"\tfunction get$uc()\n\t{\n".
    "\t\treturn \$this->$fld;\n\t}\n\n");
  # SET...
  push( @METHODS, "$line\n# Set the value of $fld.\n" );
  push( @METHODS,"\tfunction set$uc( \$$fld )\n\t{\n".
    "\t\t\$this->$fld = \$$fld;\n\t}\n\n\n");

  push( @ATTRIBUTES, "\t\t\$this->set$fld( \$attributes[$fld] );\n" );
}

########################################
# Adds a line of code to the CODE array.
sub code() {
  my $l = shift;
  push( @CODE, $l."\n" );
  
}


########################################
sub stderr() {
  my $foo = shift;
  print STDERR $foo;
}

Comments or questions?
PX is running PHP 5.2.17
Thanks to Miranda Productions for hosting and bandwidth.
Use of any code from PX is at your own risk.