Today, Michelangelo van Dam posted this narrative relating his experience with Zend Framework models:
I read the article, and wondered how hard it would be to replicate his narrative using the Solar Framework model system. Turns out it's pretty easy: there's a lot of work that Solar does for you.
-
Download a Solar system, move it to your localhost directory and make sure that the tmp
and sqlite
directories are accessible to the web server.
$ wget http://svn.solarphp.com/system/download/solar-system-1.0.0beta2.tgz
$ tar -zxf solar-system-1.0.0beta2.tgz
$ cp -r solar/* /var/www/htdocs # or your localhost directory
$ cd /var/www/htdocs # or your localhost directory
$ chmod -R 777 tmp sqlite
-
Create tables and data in sqlite/example.sq3
. There are two changes from Michelangelo's code: the table names are plural, and rename the column type_id
to address_type_id
. (These are easy enough to change in the model class definitions, but I'd like to minimize the amount of customization for this example.)
CREATE TABLE "users" (
"id" integer primary key autoincrement,
"username" varchar(255) not null,
"password" varchar(255) not null
);
CREATE TABLE "contacts" (
"id" integer primary key autoincrement,
"user_id" integer not null,
"email" varchar(255) not null,
"phone" varchar(255) null,
"fax" varchar(255) null
);
CREATE TABLE "addresses" (
"id" integer primary key autoincrement,
"address_type_id" integer not null default 1,
"user_id" integer not null,
"address1" varchar(255) not null,
"address2" varchar(255) null,
"city" varchar(255) not null,
"state" varchar(255) null,
"zip" varchar(255) not null,
"country" varchar(255) not null
);
CREATE TABLE "address_types" (
"id" integer primary key autoincrement,
"type" varchar(255) not null
);
-- Data for users table --
INSERT INTO "users"
VALUES (1, 'testuser1', 'test123');
INSERT INTO "users"
VALUES (2, 'testuser2', 'test234');
-- Data for contacts table --
INSERT INTO "contacts"
VALUES (1, 1, 'test1@example.com', '1-800-555-1234', '1-800-555-1230');
INSERT INTO "contacts"
VALUES (2, 2, 'test2@example.com', '1-800-555-2234', '1-800-555-2230');
-- Data for addresses table --
INSERT INTO "addresses"
VALUES (1, 1, 1, '1 Test Home', '', 'Testtown', 'ZF', '1234', 'PHP');
INSERT INTO "addresses"
VALUES (2, 1, 2, '2 Test Home', '', 'Testtown', 'ZF', '1234', 'PHP');
INSERT INTO "addresses"
VALUES (3, 2, 2, 'Test Corp, LTD', '4 Test Ave', 'Testtown', 'ZF', '1234', 'PHP');
-- Data for address_types table --
INSERT INTO "address_types"
VALUES (1, 'Home address');
INSERT INTO "address_types"
VALUES (2, 'Billing address');
-
Make sure the SQLite database is accessible to the web server.
$ chmod 777 sqlite/example.sq3
-
Make a vendor space for the controllers, models, suppory libraries, etc. For this example the vendor will be named Example
.
$ ./script/solar make-vendor Example
-
Edit the system configuration in config.php
. Change the front-controller class prefixes and model catalog class prefixes, and tell the SQLite adapter which file name to use.
// front controller
$config['Solar_Controller_Front'] = array(
'classes' = array('Example_App'),
// ... the rest of the front-controller array ...
);
// model catalog
$config['Solar_Sql_Model_Catalog']['classes'] = 'Example_Model';
// add sqlite config
$config['Solar_Sql_Adapter_Sqlite'] = array(
'name' => "$system/sqlite/example.sq3",
);
-
Make the model classes. Note that this avoids a ton of effort that Zend Framework requires: Michelangelo had to hand-create table, model, and mapper classes for each of the following single-line commands.
$ ./script/solar make-model Example_Model_Users
$ ./script/solar make-model Example_Model_Contacts
$ ./script/solar make-model Example_Model_Addresses
$ ./script/solar make-model Example_Model_AddressTypes
-
Edit the model classes to express what the related models are:
/** source/example/Example/Model/Users.php */
protected function _setup()
{
// chain to parent
parent::_setup();
// relateds
$this->_hasOne('contact');
$this->_hasMany('addresses');
}
/** source/example/Example/Model/Contacts.php */
protected function _setup()
{
// chain to parent
parent::_setup();
// relateds
$this->_belongsTo('user');
}
/** source/example/Example/Model/AddressTypes.php */
protected function _setup()
{
// chain to parent
parent::_setup();
// relateds
$this->_hasMany('addresses');
}
/** source/example/Example/Model/Addresses.php */
protected function _setup()
{
// chain to parent
parent::_setup();
// relateds
$this->_belongsTo('address_type');
$this->_belongsTo('user');
}
-
Make a skeleton app (i.e., a controller with its associated actions and views):
$ ./script/solar make-app Example_App_Accounts
-
Edit the controller action to fetch user account data:
/** source/example/Example/App/Accounts.php */
public $list;
public function actionIndex()
{
// get a model catalog
$model = Solar_Registry::get('model_catalog');
// populate $this->list with all users.
// eager-fetch the contact record and addresses collection.
$this->list = $model->users->fetchAll(array(
'eager' => array(
'contact',
'addresses',
),
));
}
-
Edit the view for the index action. This could be a view and a partial, but let's keep it straightforward for now.
/** source/example/Example/App/Accounts/View/index.php */
<table>
<tr>
<th>Username</th>
<th>E-Mail</th>
<th>Phone</th>
<th>Fax</th>
<th># addresses</th>
</tr>
<?php foreach ($this->list as $user): ?>
<tr>
<td><?php echo $this->escape($user->username); ?></td>
<td><?php echo $this->escape($user->contact->email); ?></td>
<td><?php echo $this->escape($user->contact->phone); ?></td>
<td><?php echo $this->escape($user->contact->fax); ?></td>
<td><?php echo count($user->addresses); ?></td>
</tr>
<?php endforeach; ?>
</table>
You're done. Browse to http://localhost/index.php/accounts/index
to see the results of your handiwork.
Total elapsed time from when I read Michelangelo's article to come up with the Solar conversion and write this article: under two hours.