Multiple Database Connections with Solar Dependency Injection

Posted in PHP, Solar on February 24th, 2011 by Jon – 1 Comment

In an email the other day, a person asked about being able to connect to multiple databases in Solar. While this is quite easy to do, it probably isn’t officially documented anywhere. If you poke around in Solar’s code, you will soon discover that it can be accomplished using dependency injection (technically this is a combined dependency injection and service locator).

Each of your application’s models extend the Solar_Sql_Model class. If you examine the Solar_Sql_Model class, you’ll notice that one of the config elements is ‘sql’. This is a key that refers to a Solar dependency. The default value for this is key is ‘sql’. That might seem strange at first. How is the string ‘sql’ a dependency? Well, first, we need to dig into the Solar_Sql_Model class. In the _preSetup() method there is a call to Solar::dependency(), which populates the $_sql property using the config[‘sql’] element.

protected function _preSetup()
{
...
// connect to the database
$this->_sql = Solar::dependency('Solar_Sql', $this->_config['sql']);
}

The first parameter is a hint to the the type of object, and the second is either an object OR a string that refers to an object in Solar’s registry. If you remember, the default value of Solar_Sql_Model’s ‘sql’ config element was a string ‘sql’. Therefore, there must be an object in Solar’s registry named ‘sql’. If not, Solar will throw and exception.

If you look at the Solar vendor’s default config (SYSTEM/source/solar/config/default.php) you will see the following:

$config['Solar']['registry_set'] = array(
    'sql'=>'Solar_Sql',
    'user'=>'Solar_User',
    'model_catalog'=>'Solar_Sql_Model_Catalog',
    'mail_transport'=>'Solar_Mail_Transport',
    'controller_front'=>'Solar_Controller_Front',
);

The ‘sql’=>’Solar_Sql’ tells Solar to register a Solar_Sql object in the registry keyed on the string ‘sql’. If you look again at the default.php config file, you should see a config entry for for Solar_Sql where you can define the options for the Solar_Sql object.

/**
* sql adapter to use
*/
$config['Solar_Sql'] = array(
    'adapter' => 'Solar_Sql_Adapter_Sqlite',
);

That is the background information. To summarize what we now know…

  1. Solar’s models connect to the database using a dependency injection/service locator keyed on the string ‘sql’.
  2. Because the default value for the ‘sql’ key is the string ‘sql’, then we know we are looking for something located in Solar’s registry.
  3. Looking at the Solar default.php config file, we see that there is a ‘registry_set’ config element indicating that ‘sql’ should be registered in the registry as a Solar_Sql object.
  4. Finally, the Solar_Sql object is also configured in the default.php file, and in our example, it is configured to use Solar_Sql_Adapter_Sqlite as its adapter class.

Understanding how this works, we can start setting up other sql dependencies to be used by our models. Here is one way you can do it.

First, we need to add another item to our registry. We can call it ‘sql_acme’. One thing to note is that you can specify an array as its value in the registry, not just a class name. It might look like this:

// configuration for the acme Solar_Sql object to be added to the registry
$sql_acme = array(
    'adapter'=>'Solar_Sql_Adapter_Mysql',
    'host'=>'localhost',
    'name'=>'acme',
    'user'=>'juser',
    'pass'=>'S3cr3t'
);
 
// define what will be added to the regsitry
$config['Solar']['registry_set'] = array(
    'sql'=> 'Solar_Sql',
    'sql_acme'=>array('Solar_Sql', $sql_acme),
    'user'=> 'Solar_User',
    'model_catalog'=>'Solar_Sql_Model_Catalog',
    'mail_transport'=>'Solar_Mail_Transport',
    'controller_front'=>'Solar_Controller_Front',
);

Now, we need to tell Solar what registry entry to use for one of our models. You can set that up like this. Assume the model is for a table of articles.

$config['Acme_Model_Articles']['sql'] = 'sql_acme';

That’s all there is to the setup and configuration. There is, however; one important thing to keep in mind. If you are using Solar’s command line tools to create your models then, by default, Solar will use the default ‘sql’ dependency since it can’t read the configuration for a model that doesn’t yet exist. Luckily, you can specify the required configuration options at the command line. For example, if your user credentials and host were the same for both databases, and the only difference was the database name, then you could do this:

$ ./script/solar make-model Acme_Model_Articles --name acme

If you want to know all the options available to the make model (or any) command, use the following:

$ ./script/solar help make-model

So that is one way you can set up multiple databases at the model level in Solar. You can also set up multiple databases for each vendor. I will save that for another post.

SimpleXML + Solar’s Alternate Formats = Easy RSS

Posted in PHP, Solar on February 17th, 2011 by Jon – 1 Comment

Creating your own RSS feeds is generally straightforward, but it’s even easier when you combine PHP’s SimpleXML and Solar’s alternate format mechanism.

If you are new to Solar, you better check out the manual.

Setup Solar

Solar makes it easy to specify an alternate format simply by changing the extension of your request. For example, say you have a list of articles at

http://www.example.com/articles/browse

Here, “articles” refers to the controller, and “browse” refers to the action. By default, no format was explicitly specified, so the default text/html is used when outputting the content to the browser. If you wanted to use an alternate format, you can specify the format by using an extension. Here are a couple of examples:

  • http://www.example.com/articles/browse.rdf (application/rdf+xml)
  • http://www.example.com/articles/browse.xml (application/xml)

Before these will actually work, you have to perform a couple of tasks in your Solar environment.

First, you need to tell Solar that a given format (or formats) are allowed for a given action. Do this by adding code to the top of the Articles.php application controller.

<?php 
protected function _setup()
{
    // chain to parent
    parent::_setup();
 
    // allow xml and rdf formats for the browse action
    $this->_action_format = array(
        'browse'=>array('xml', 'rdf')
    );
}
?>

Second, you need to create an appropriate view for each format specified. In the example above, you need two new views. One for the xml format, and one for the rdf format. The naming convention for each view is as follows:

  • browse.xml.php
  • browse.rdf.php

Now, when browsing to http://www.example.com/articles/browse.xml, Solar will use the browse.xml.php view and output accordingly.

Create Markup with SimpleXML

Before using SimpleXML to format the xml output, it’s assumed that we have a collection of article records to work with, and that they are available to the view as $this->list.

Inside the browse.xml.php file…

<?php
 
// Get the current URI
$uri = Solar::factory('Solar_Uri_Action');
$uri->format = null; // reset the format
$link = $uri->get(true); // get the full uri, including http:// etc
 
$xml = new SimpleXMLElement('<rss version="2.0"></rss>');
$channel = $xml->addChild('channel');
$channel->addChild('title', 'My RSS Feed');
$channel->addChild('link', $link);
$channel->addChild('description', 'My RSS feed about something of interest');
$channel->addChild('language', 'en-ca');
$channel->addChild('pubDate', $this->list[0]->date_added); // assume the list in chronologically ordered
$channel->addChild('lastBuildDate', $this->list[0]->date_added.' MST');
$channel->addChild('webMaster', 'me@example.com');
foreach ($this->list as $item) {
	$uri->path = 'articles/read/' . $item->getPrimaryVal(); // set up the path to each article
	$title = $channel->addChild('item');
	$title->addChild('title', $this->escape($item->title));
	$title->addChild('link', $this->escape($uri->get(true)));
	$title->addChild('description', $this->escape($item->description));
	$title->addChild('pubDate', $this->date($item->date_added, "D, d M Y")); // Solar's date() view helper
}
echo $xml->asXML();
?>

And that’s basically all there is to it! Browse to http://www.example.com/articles/browse.xml and you should see an xml version of the page.

References

Add validation filters before saving in Solar

Posted in PHP, Solar, Uncategorized on October 22nd, 2010 by Jon – Be the first to comment

I have preached about how Solar makes my web development life so much easier, and here is another example of why.

Every once in a while, I have to add or modify my record validation before it is saved in the database. For example, I am working on a publication database where a publication has several availability “flags”, such as

  • available as pdf,
  • available in print,
  • available as pdf by email

In this scenario, all three can be “unchecked”, however; available as pdf and available as pdf by email can NOT both be checked. So, to validate that, I use a pre-save hook in the publication record class and set a filter.

<?php
class Bookstore_Model_Publications_Record extends Bookstore_Sql_Model_Record
{
    protected function _preSave()
    {
        parent::_preSave();
        // Check to make sure that email_pdf and pdf are not both checked
	if ($this->_data['available_pdf'] == '1' && 
            $this->_data['available_pdf_email'] == '1') {
                $this->addFilter(
                    'available_pdf_email', 
                    'validateNotEquals', 
                    'available_pdf'
                );
	    }
	}
    }
}
?>

So, basically, before the record is saved, I look to see if available_pdf == 1 AND available_pdf_email == 1 and if so, add a new validation filter on available_pdf_email. The new filter is called “validateNotEquals” and you pass the name of a field you don’t want to allow it to be the same as. In this case available_pdf.

With this filter added, the record won’t save and will display an error message under available_pdf_email.

Simple.

New Gear

Posted in Camping, Running on June 28th, 2010 by Jon – Be the first to comment

I’ve had to retire my old training watch. It’s a Suunto T3 and has performed well over the last few years. I broke the strap for the second time and it’s over $20 to replace and a special order. That’s a pain in the butt. Also, the heart rate strap seems to have stopped working. So now, it’s just a stopwatch. I didn’t want to spend a bunch of money fixing it and the like so I bought a cheaper replacement. It’s a basic Timex Ironman Road Trainer HRM for only $105 from Mountain Equipment Coop (MEC). It has fewer features, but I think I will survive without them. The one I will miss is the interval timing. I try to run intervals once a week and being able to set two separate interval times is nice (run hard for 2 minutes and rest for 1 minute). Today will be my first day with the new watch so we will see how it goes.

I also replaced our screen tent. My family are tenters, so having a decent shelter for cooking and eating is a must. Our old screen tent was heaving and failing so it was time for a replacement. I picked up a Hootenanny from MEC and set it up yesterday. So far it’s great! Not sure how it will do in a steady rain, but I can always tarp it. Now I just have to get out and use it!

Solar Framework Goes Beta

Posted in PHP, Solar on January 5th, 2010 by Jon – Be the first to comment

On January 1, 2010, the beta2 of the Solar MVC PHP framework was released. Additionally, a new “Beginner’s Guide” was posted, which will be a great help to anyone wanting to try out a great PHP Framework.

Happy new year!

Some like it cold

Posted in Weather on December 14th, 2009 by Jon – Be the first to comment

We have had a pretty bad cold snap for the last few days. A few broken records for low temperature too. The other night, we hit -46.1 C and the wind chill would have made it feel like -59 C. We were the second coldest place recorded on Earth. A location in Siberia recorded -48 C. Brrrrr.

A screenshot from Environment Canada's website showing the minimum temperature

A screenshot from Environment Canada's website showing the minimum temperature

Start Using a Top Quality Framework “Right Now”

Posted in PHP, Solar on November 13th, 2009 by Jon – Be the first to comment

Paul M. Jones has what I will call a “fun” post on is blog. There may be some “cheerleading”, but I welcome it. His post points to several areas where the Zend Framework (ZF) developers will be implementing approaches already available in Solar. This is by no means framework-bashing. It’s about letting people know that a top quality framework is available right now. So what are you waiting for? Get started.

Invalid RSS Feeds

Posted in PHP on November 12th, 2009 by Jon – Be the first to comment

I created a simple feed parser for Solar the other day. I am using this on our corporate Intranet. It works pretty well so far and uses Solar_Cache to periodically store the data for fast retrieval. The parser uses PHP’s SimpleXMLElement. Today I found a feed that wasn’t showing up properly. After some digging, it turned out that it was because the feed itself was not valid; it had extra content after the closing rss tag. The last bit of content looked like some sort of stats tracking image and some comments. Invalid RSS feeds are too common, IMHO. The problem is, that the tools we use to parse the feeds get stuck with the job of finding workarounds to the invalid feed data. What would be better is if more people complained that the feeds were invalid, forcing the author to fix them. This would make building simple feed readers a whole lot easier.

Gear Addiction

Posted in Camping on September 10th, 2009 by Jon – Be the first to comment

Ever since I was a kid I have loved hiking and camping gear. Backpacks, ropes, tents, knives and all that great stuff that goes along with camping. Since being a “grown up” with responsibilities, that addiction was replaced with other important things. This summer, however, the gear addiction was somewhat rekindled.

During my week off in the Summer, I spent the majority of my time in the outdoors, taking pictures, and doing fun things like making bows and arrows for my kids (well kind of mostly for me), and watching a lot of Survivorman (I love that Survivorman (Les Stroud) is a Canuck). I became more and more enthusiastic about the outdoors, survival and general camping. I took the family camping a couple of times – once to Jasper and once to Elk Island National Park. Great fun, even though it was terribly cold and rainy in Jasper. In the last several weeks I have pretty much worn out my MEC catalog and visited their web site countless times. I haven’t really even purchased anything (just a tent). I just spend all my time looking and drooling over all the gear. And it’s not that I need much in the way of gear. I just like to look at it! For example, I hate heights and will never really do any climbing, but I am fascinated by climbing gear. My older daughter is starting a climbing class this fall and I think it’s so great. What a cool thing for a 5 year-old to do! Anyway, I think I will stop now and go look at new sleeping bags. Mine is getting pretty worn out.

Solar Alpha3

Posted in Solar on September 10th, 2009 by Jon – Be the first to comment

After about a year, Solar has moved from version 1.0.0alpha2 to 1.0.0alpha3. Yes, it’s been a while, but when you realize that only one person really works on the project in his spare time, that’s a pretty good achievement. This whole spare time thing is also changing. Solar is about to get a whole lot more attention now that the developer’s employer (OmniTI) has agreed to let him use up to 40% of his paid work time to further develop Solar. Obviously, OmniTI knows a good thing when they see it.

As of writing this, Paul hasn’t had time to update the Solar site with the latest download, but that will likely happen tomorrow. Additionally, there will be a nice post about what has changed. I will add some links when they are available.

Anyone who has used a PHP web framework before, or those who just wants to try one out, should give Solar a whirl. It is the most well-thought-out framework I have had the pleasure of using. What’s next for me? Time to checkout the latest from SVN and give it a work out. The faster we test it and iron out bugs, the sooner there will be a beta release. On that note, a beta release is actually not far off and (hopefully) by the end of the year, the official stable release will be available.