Archive for February, 2011

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