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