Framework Update
Over the past few months I’ve been working on a large application powered by my vBulletin MVC framework which required me to make several improvements. One of the models I was working with had about 40 fields, and that caused me to generate all the forms dynamically from model variables dedicated to defining forms. 600 lines of configuration per model later, I grew pretty fed up.
After looking around at other frameworks for fun, I stumbled upon Symfony’s use of Propel, which is a code generator for database access. That got me thinking… At least for initial development, 80% of the work is setting up the initial models, controllers and database tables. Making changes to these are also very tedious, so that inspired me to dig a little deeper and see what I could automate.
After a few hours of tinkering, I managed to get a working copy running (still have to do table schema, but that’s easy). Based on an application configure file, it generates the models, form definitions including validation, controllers, and even action code for index (paginated), view, add and edit. Fully working.
Since we are human and never get anything right the first time, code not in isolated files are wrapped in special comment tags so they can be manually edited without losing the ability to regenerate the dynamic sections.
Examples below. SVN has been updated with the latest code, minus the full generator code as it’s still in development, but the templates are there. Still unstable.
Application Config XML
-
<?xml version="1.0"?>
-
<application id="product_id">
-
<data>
-
<table name="user">
-
<columns>
-
<column name="userid" auto="true"/>
-
<column name="username" title="Username">
-
<datatype>varchar(255)</datatype>
-
<validation type="string">min(3)</validation>
-
<description>The username of the surgeon</description>
-
</column>
-
<column name="password" title="Password">
-
<datatype>varchar(32)</datatype>
-
<validation type="string">min(3)</validation>
-
<description>Your password</description>
-
</column>
-
<column name="email">
-
<datatype>varchar(45)</datatype>
-
<validation type="string">call(’verify_email’)</validation>
-
<description>Your email address.</description>
-
</column>
-
<column name="fullname">
-
<datatype>varchar(75)</datatype>
-
<validation type="string">min(5)->no_html()</validation>
-
<description>Your full name.</description>
-
</column>
-
<column name="phone">
-
<datatype>varchar(32)</datatype>
-
<validation type="string">min(5)->no_html()</validation>
-
<description>Your phone numjber.</description>
-
</column>
-
</columns>
-
</table>
-
</data>
-
<!– with the following forms ready for generation –>
-
<forms>
-
<form id="new-user" table="user">
-
<group name="Primary Account Information">
-
<field name="username"/>
-
<field name="password"/>
-
<field name="password" confirm="true"/>
-
<field name="email"/>
-
</group>
-
<group name="Member Profile">
-
<field name="fullname"/>
-
<field name="phone"/>
-
</group>
-
</form>
-
</forms>
-
</application>
Model
-
<?php
-
-
class FW_Model_User extends FW_Model_App
-
{
-
-
/**+~~ genStart ~~+**/
-
-
var $table = ‘user’;
-
-
var $key = ‘id’;
-
-
‘userid’,
-
‘username’,
-
‘password’,
-
‘email’,
-
‘fullname’,
-
‘phone’
-
);
-
-
/**+~~ genStop ~~+**/
-
-
}
-
-
?>
Form Definition
Form Input
Controller - Index
-
<?php
-
-
class FW_Action_Users_Index extends FW_Action_Users
-
{
-
‘index_template’,
-
‘index_template_bit’
-
);
-
-
‘root_url/’ => ‘Root Title’,
-
‘Index Page’
-
);
-
-
-
-
protected function clean_request_params()
-
{
-
$this->page = $this->Input->new_item(‘u’, ‘page’, ‘integer’)
-
-> get();
-
-
/*
-
$this->Pagination->set_record_type(’pagination_type’);
-
$this->Pagination->set_current_page($this->page);
-
$this->Pagination->set_per_page($this->options[’items_pp’]);
-
-
$this->User->enable_pagination($this->Pagination);
-
*/
-
}
-
-
public function display($input = null)
-
{
-
-
$recordbits = $this->construct_record_bits();
-
#$pagination = $this->Pagination->render(true);
-
-
}
-
-
protected function construct_record_bits()
-
{
-
$bits = ”;
-
$color = ‘alt2′;
-
-
foreach ($this->User->fetch_all() as $comment)
-
{
-
$color = $color == ‘alt1′ ? ‘alt2′ : ‘alt1′;
-
}
-
-
return $bits;
-
}
-
-
public function construct_navbits()
-
{
-
-
-
-
$this->breadcrumbs = array_combine($urls, $titles);
-
-
return parent::construct_navbits();
-
}
-
-
}
-
-
?>
Controller - Edit
-
<?php
-
-
class FW_Action_Users_Edit extends FW_Action_Users
-
{
-
‘edit_template’
-
);
-
-
‘root_url/’ => ‘Root Title’,
-
‘root_url/view/%d’ => ‘%s’,
-
‘Edit’
-
);
-
-
-
-
protected $id;
-
protected $info;
-
-
protected $form_id = ‘edit_user’;
-
-
protected function clean_request_params($params)
-
{
-
$this->id = $this->Input->new_value($params[0], ‘id’, ‘integer’)
-
-> get();
-
-
$this->info = $this->User->fetch($this->id) or
-
$this->error(‘Invalid page specified.’);
-
}
-
-
public function display($input = null)
-
{
-
-
$data = $this->info;
-
-
if ($input)
-
{
-
$errors = $input->errors;
-
}
-
-
$form = $this->HTML->form($this->form_id, $data, $errors);
-
}
-
-
public function submit()
-
{
-
$input = $this->Input->handle_form($this->form_id);
-
-
{
-
return $this->display($input);
-
}
-
-
// entire array is saved, so modify if necessary
-
-
$this->User->update(‘user’, $save);
-
-
$this->redirect("view_url/$this->id", ‘Saving Record’);
-
-
}
-
-
public function construct_navbits()
-
{
-
-
-
$this->breadcrumbs = array_combine($urls, $titles);
-
-
return parent::construct_navbits();
-
}
-
}
-
-
?>



This is a great idea that has a lot of potential, but I have a few questions:
1) What is this construct that you have:
[PHP]
$object -> method()
->method2
-> method3
[/PHP]
I assume you are intending to call different methods of the same object in sequence. But is there such a construct? I mean, if I just say $obj->method()->method2(), then the manual defines this as “calling method2 of the obj returned by $obj-method()”. Unless each of your methods returns an object, this wouldn’t make a lot of sense in your context. Please explain.
2) Where is the actual code generator, is it available somewhere for download?
Also, maybe we can cooperate on creating this one too? I’m very interested, except I would like this to be taken a step beyond vbulletin, such that it could be used to generate standalone code for use in any context.