version: #1 (current)  |  last edited by: Mike Ho  |  on: saturday, october 22, 2005, 2:35 am pdt (about 13 years ago)


This article will hopefully give you a brief overview and understanding of the Code Generator part of Qcodo.  It will step you through creating your first table and class, and shows you how to where to begin to make changes to implement visual design, business rules or data model rules (adding, removing or changing columns, etc).



NOTE: This article covers Beta 1 of the framework.  If you want documentation for Beta 2, please check out the <a href=“http://examples.qcodo.com/” class=“link_body”>Examples Site</a>.


This will hopefully take you through a basic quickstart of using the code generator.  It assumes that you have successfully installed the Qcodo framework, and that you have verified it is working.  If you need assistance with this, please refer to <a href=“/documentation/article.php/1” class=“link_body”>Installing the Framework</a>

Creating a Database

Qcodo's code generator only generates its code off of an active database schema.  Assuming that you have the database configured properly, you can use the MySQL GUI tools or use the command-line tool to run the following few commands to set up a new sample database in MySQL.  The rest of the article assumes that you have a standard MySQL database server set up on your local machine, and that you have access to MySQL “root”, with no password configured (which is the default setting for newly configured MySQL servers).  Feel free to change any of the commands in this document to suit your specific needs.

setup a sample database

> cd /path/to/mysql/bin (if it is not already configured as a PATH in your shell environment)
> mysql -u root mysql

mysql> CREATE DATABASE sample;
mysql> exit;

>

Next, you will want to update your _configuration.inc file to correctly setup the database connection.

Listing of /includes/_configuration.inc

<?
    define('SERVER_INSTANCE', 'dev');
    
    switch (SERVER_INSTANCE) {
        case 'dev':
        case 'test':
        case 'stage':
        case 'prod':
            define('DBCONFIG_1', 'MySqliDatabase');
            define('DBCONFIG_1_SERVER', 'localhost');
            define('DBCONFIG_1_NAME', 'sample');
            define('DBCONFIG_1_USERNAME', 'root');
            define('DBCONFIG_1_PASSWORD', '');
            break;
    }    
?>

The reason for the switch statement and the SERVER_INSTANCE constant is to allow the developer to easily set up multiple configuration options for different environments.

Note that the constant that you define includes the number “1”, as in DBCONFIG_*1*.  This tells the framework that our connection information for the sample database is in database connection #1.  Out of the box, Qcodo can support up to 10 different simultaneous database connections (and actually, Qcodo technically supports an unlimited number if needed).  This allows your web application to interface with any number of databases.  Utilizing the Code Generator to generate the objects that map back to these databases, you can create an entire library of objects for your Object Relational Model for multiple databases in a way that is completely encapsulated from the developer from having to have to manage those individual database connections.

You'll also note that the database specified is MySql*i*Database.  The extra “i” is not a typo.  With version 5 of PHP, the MySQL Improved extension was released, and it is recommended that developers use the MySQL Improved extension over the old one.  Qcodo actually provides support for both the improved and the old extensions, although we would recommend that you use the improved extension whenever possible.  If you wish to use the Qcodo database adapter which utilizes the old MySQL extension, simply change the configuration to say “MySqlDatabase”, removing the “i”.

Our First Table

We want to create a simple, sample table.  Let's create a project table.  Do this by running the following SQL script using either the command line tools or the MySQL GUI tools.

Listing of a “Create Project” SQL script

    CREATE TABLE project (
        id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
        name VARCHAR(100),
        CONSTRAINT PK_project PRIMARY KEY (id)
    );

The Qcodo code generator allows you to specify any name and any type/kind of primary key for your tables that you wish to code generate off of.  Any tables that have no primary keys will simply be ignored by the code generator (e.g. no code will be generated for it).  And in fact, Qcodo even allows tables to have multiple-column primary keys.  However, only limited functionality will be generated for tables that have multiple primary keys.

This level of flexibility is mostly to suit projects that wish to code generate off of legacy or existing databases.  Whenever designing new data models (as we are doing here), it is strongly recommended to stick with a single primary key of arbitrary value, which would be “INTEGER UNSIGNED NOT NULL AUTO_INCREMENT”.

Generating Code

The code generator can be run by running the index.php script in /codegen/ in a web browser.  In actuality, the Code Generator is a class that is defined in the qcodo framework (within /docroot/includes/qcodo/codegen/CodeGen.inc), and the /docroot/codegen/index.php script is simply a web front-end for that Code Generator class.  So it would be trivial to write your own web front-end or even command-line based version of the Code Generator, in case you want to include code generation in a custom build script or automated process of some sort.

Taking a quick look at the web front-end of codegen, you'll see that only the top dozen or so lines (including comments) directly deal with the CodeGen object.  Everything else past it is simply to paint a pretty HTML page to display the results.

Listing of codegen/index.php

<?
    require_once('prepend.inc');
    require_once('qcodo/codegen/CodeGen.inc');

    // Setup Your Preferences Here //
    
    // Specify Which Database Index (from the _configuration.php script) to CodeGen Against
    // as well as specific Other Settings Here
    $strSettingArray = array(
        'DatabaseIndex' => 1,
        'ClassPrefix' => '',
        'ClassSuffix' => '',
        'TypeTableSuffix' => '_type',
        'AssociationTableSuffix' => '_assn',
        'TemplateEscapeBegin' => '<%',
        'TemplateEscapeEnd' => '%>',
        'AssociatedObjectPrefix' => ''
    );

    /////////////////////
    // Run Code Gen    
    $objCodeGen = new CodeGen();
    $objCodeGen->AnalyzeDatabase($strSettingArray);
    /////////////////////



    // Report the Results in a pretty page...
    $strReport = '';
    if ($objCodeGen->TableArray) foreach ($objCodeGen->TableArray as $objTable) {
        if ($objCodeGen->GenerateTable($objTable))
            $strReport .= sprintf("Successfully generated class:       %s\n", $objTable->ClassName);
...

One thing to realize is that CodeGen's main method “AnalyzeDatabase” takes in a SettingsArray, which is an array of name value pair strings.  The most important setting you must always include is the DatabaseIndex, so that the Code Generator knows which database connection # to use.  In our example, we setup the sample database to be accessed on database connection #1.  So the above code snippet from codegen/index.php should work just fine.

So let's go ahead and run the code generator by going to http://localhost/codegen/ in a web browser.  If it worked, it should report that “no errors were reported” and that it successfully generated the “Project” class.

Understanding what the Code Generator Generates

For each table in the database (in this case, “project”) that the code generator generates code for, a whoppin' eight files are created:



  • /docroot/includes/data_objects/Project.inc
  • /docroot/includes/data_objects_generated/ProjectGen.inc
    and
  • /docroot/form_drafts/project_edit.php
  • /docroot/form_drafts/project_list.php
  • /docroot/form_drafts/generated/project_edit.php.inc
  • /docroot/form_drafts/generated/project_list.php.inc
  • /docroot/includes/forms_generated/ProjectEditFormBase.inc
  • /docroot/includes/forms_generated/ProjectListFormBase.inc


Now, at first glance, this seems very daunting.  But let's break it down a little bit and hopefully it will be easier to digest.

Remember that the Qcodo Code Generator generates code to handle two things:
<ol>
* the Object Relational Model, or the code that performs the Database Table to Object mapping
* the HTML Form Drafts, or the code that handles the Object to HTML mapping via the use of Qforms
</ol>

Code Generation of Data Objects

For (1), only two files are generated. Project.inc (in includes/data_objects) and ProjectGen.inc (in includes/data_objects_generated).  ProjectGen.inc contains all the basic CRUD-type method to create, restore, update, and delete project data to/from the database.  Later on, you will see that it will also provides more complex methods to retrieve by index, associate and unassociated related objects, and perform early- and late-binding on those related objects.

But for now, just realize that ProjectGen.inc is the generated object relational model for the project table.

The Project.inc file is more or less a blank Project class that extends the ProjectGen class.  Throughout the system, calls to Project should be done on the Project class and not the ProjectGen class (and in fact, doing so will throw an error because ProjectGen is an abstract class).

ProjectGen.inc will always be recreated on subsequent calls to the code generator.  However, Project.inc will never be recreated.  Any changes to that file will not be overwritten.

This design is to allow developers to write custom functionality, implement business logic, etc. in Project.inc, but still allow developers to re-code generate as often as possible, without fear of losing any of his/her customizations, changes, etc.

Code Generation of Form Drafts

For (2), the remaining 6 files are code-generated implementations of the Qform class, for the PHP front-end HTML code to view, create, edit and delete Project objects from the system.

Three of the files are used for the “List All Projects” page, and the other three files are used for the “Edit a Project” page.  The “Edit a Project” page actually contains functionality to create, edit, and delete an individual project.

For both Edit and List, they each have three files each.  A form draft PHP page, a form draft include file (the HTML template) for that PHP page, and a FormBase object.

(For more information about Qforms, as well as the Form objects itself, please refer to <a href=“/documentation/article.php/3” class=“link_body”>QuickStart Guide: Qforms</a>)

Now, in reality, because qform pages are really only just two files, we could have simply generated (for the Project Edit page) a project_edit.php file and a project_edit.php.inc file to have a draft “Edit” page, where the .php file has the display logic and the .php.inc file be the HTML template.

But the Code Generator basically splits project_edit.php into two files:

  • project_edit.php is a ProjectEditForm class
  • /includes/form_drafts/ProjectEditFormBase.inc, which is a ProjectEditFormBase class


The reason for this split is the exact same reason we generated Project.inc and ProjectGen.inc: any customizations we do to the Edit page (e.g. add new controls, implement any sort of visual design, implement display-level logic, etc.) should be done in the subclass in the project_edit.php page.  And of course, an added advantage is that we can rename project_edit.php to whatever.php, and move both the .php and its HTML include/template (.php.inc ) files both to wherever we want in the docroot.

However, because the Edit page still extends ProjectEditFormBase, which is a code-generated class, the Edit page can take full advantage of code regenerations whenever references, columns and indexes are added/removed/changed to the project table.

This is definitely a key value of the Qcodo code generator and the way that it interacts with creating Qforms.  It allows you a great starting point to help you design out the pages/screens for your application.

(Keep in mind that form drafts are not always the best starting point for certain screens in your application.  A good candidate for a designed screen is when you have more than half or 2/3rds of the controls and display logic on that screen was code generated will be used on the screen.

Otherwise, sometimes it might be a better idea to just start from scratch or to copy and paste the snippets of code from these generated files, but to create a new one from scratch.

Playing Around with your Generated Code

Now, you should be able to just go to /form_drafts/index.php in a webbrowser and play around with listing, creating, editing and deleting projects to your database.

Go ahead and add new tables, link them together with foreign keys (if you are using MyISAM, please refer to <a href=“/forums/topic.php/3” class=“link_body”>this forum topic</a> on how to tell the code generator about FK links even though MyISAM doesn't support FKs), make things null or not null, play around with various MySQL data types, etc.

Just remember to regenerate the code (by just refreshing the webpage at /codegen/index.php whenever you make any change in the data model.

And then if you get more daring, go ahead and write custom business-logic functionality in the data object code, or write custom display-logic functionality in your form draft objects and pages.



Copyright © 2005 - 2019, Quasidea Development, LLC
This open-source framework for PHP is released under the terms of The MIT License.