Paul M. Jones

Don't listen to the crowd, they say "jump."

Solar 0.21 and 0.22 released in quick succession

I released Solar 0.21.0 yesterday, and a quick followup 0.22.0 today. The rest of this entry covers highlights for changes in both versions. The main highlights are three new classes (Solar_Struct, Solar_Sql_Row, and Solar_Sql_Rowset) along with a backwards-compatibility break to how classes store their default configuration values.

Changes To $_config Use

There is one really big change to the configuration system. It should not require more than a search-and-replace in your files, but it's still a big deal.

The change is that you now put the default config values for your class in a property called $_{Class_Name} instead of in $_config. (Keep using the $_config property for reading configs, but put the defaults in $_{Class_Name}.) For example ...

Previously, you would do this to define a default config key and value:


<?php
    // parent class
    class Vendor_Foo extends Solar_Base {
        protected $_config = array('foo' => 'bar');
        public function getConfig()
        {
            Solar::dump($this->_config);
        }
    }

    // child class
    class Vendor_Foo_Baz extends Vendor_Foo {
        protected $_config = array('baz' => 'dib');
    }
?>

This was great for reading from the config file, but it meant that the parent class config keys were not inherited by the child class. The child $_config overrides the parent $_config entirely; you would have to put some checking code in your parent constructor to make sure all the keys were there. Thus, a call to Vendor_Foo_Baz::getConfig() would show only the 'baz' key, and not the combination of the parent 'foo' key and the child 'baz' key.

In this release, we change from $_config to $_{Class_Name} for default config values.


<?php
    // parent class
    class Vendor_Foo {
        protected $_Vendor_Foo = array('foo' => 'bar');
        public function getConfig()
        {
            Solar::dump($this->_config);
        }
    }

    // child class
    class Vendor_Foo_Baz extends Vendor_Foo {
        protected $_Vendor_Foo_Baz = array('baz' => 'dib');
    }
?>

(Note from getConfig() that the $_config property does not go away, you just don't put anything in it yourself.)

In the new system, Solar_Base collects all the $_{Class_Name} arrays and merges them all into $_config for you. This means that child classes inherit their parent config keys and values unless you override them in the child class.

Basically, you should keep reading from $_config when getting config values in your class methods. But for property definitions, use $_{Class_Name} for the default config keys and values.

Solar_Struct

The new Solar_Struct class is an ideological cousin to Matthew Weier O'Phinney's Phly_Hash class (originally Phly_Struct).

When you build a struct instance, you give it a series of keys and values as an array; those keys become properties in the struct object, and the values are used as the property values.


<?php
    $data = array(
        'foo' => 'bar',
        'baz' => 'dib',
        'zim' => 'gir',
    );

    $struct = Solar::factory(
        'Solar_Struct',
        array('data' => $data)
    );
?>

Using this class, you can access data using both array notation ($foo['bar']) and object notation ($foo->bar). This helps with moving data among form objects, view helpers, SQL objects, etc.


<?php
    echo $struct['foo']; // 'bar'
    echo $struct->foo;   // 'bar'
?>

The struct object implements ArrayAccess, Countable, and Iterator, so you can treat it just like an array in many cases.


<?php
    echo count($struct); // 3

    foreach ($struct as $key => $val) {
        echo "$key=$val ";
    } // foo=bar  baz=dib zim=gir
?>

One problem with Solar_Struct is that casting the object to an array will not reveal the data; you'll get an empty array. Instead, you should use the toArray() method to get a copy of the object data.


<?php
    $array = (array) $struct;    // $struct = array();
    $array = $struct->toArray(); // $struct = array(
                                 //     'foo' => 'bar',
                                 //     'baz' => 'dib',
                                 //     'zim' => 'gir',
                                 // );
?>

One other problem is that double-quote interpolation isn't as intuitive. If you want to use a struct property in double-quotes, you should wrap it in curly braces.


<?php
    // won't work right, will show "Object #23->foo"
    echo "Struct foo is $struct->foo";

    // will work as expected
    echo "Struct foo is {$struct->foo}";
?>

Solar_Sql_Row

The new Solar_Sql_Row class is extended from Solar_Struct, and adds a new method called save().

From now on, any time you call select('row') or fetch() from an SQL class, you're going to get a Solar_Sql_Row object instead of an array. Because Solar_Struct acts like both an array and an object, you shouldn't have to change any of your code to use the new return type.

If you want to, you can start using object notation with rows. For example, instead of $row['id'] you can use $row->id (which is a lot easier to read in most cases).

An additional benefit is that Solar_Sql_Row has a save() method that can be tied back to a table object. Previously, if you wanted to insert or update a row, you had to pass it as an array into its related table object:


<?php
    $row['foo'] = "bar";
    $row['baz'] = "dib";
    $table->save($row);
?>

Now you can save the row directly:


<?php
    $row->foo = "bar";
    $row->baz = "dib";
    $row->save();
?>

Because it is tied back to the source table object, it follows all the validation and insert/update rules of that object, so you don't need to duplicate them just for the row object.

Solar_Sql_Rowset

The new Solar_Sql_Rowset class also extends from Solar_Struct, but it works as a collection of Solar_Sql_Row objects. You can iterate through it with foreach() and get one row at a time, working with each and calling save() as you go.

From now on, any time you call select('all') or fetchAll() from an SQL class, you're going to get a Solar_Sql_Rowset object instead of an array. Because Solar_Struct acts like both an array and an object, you shouldn't have to change any of your code to use the new return type.

User-Defined Row Classes

With Solar_Sql_Row and Solar_Sql_Rowset in place, Solar_Sql_Table now returns these when you call fetch() and fetchAll(). Even better, you can set the new properties $_row_class and $_all_class to a custom class descended from a Row or Rowset; if you do, the fetch*() methods will use those classes as the return objects. This paves the way for the beginning of something like a formal ActiveRecord pattern as described by Martin Fowler (as opposed to the one popularized by Rails.)


Solar-Talk Archives Now Searchable

Rodrigo Moraes just set up a web interface to search the Solar-Talk mailing list. From his announcement on Solar-Talk:

The Solar-talk archives are now searchable:

http://tipos.org/solartalk/

It is a very rudimentary mini-app using Solar & Zend_Search_Lucene for the indexing. Some features are still not implemented like pagination and exact phrase match. Messages will be indexed once a day via cron, starting from today at night. Currently it is indexed until last Friday, July 14.

I needed this. Hope others will also find it useful. :-)

Thanks Rodrigo!


Input Tags In Forms Not Valid XHTML

(I'm stuck at Sky Harbor in Phoenix because of a delayed flight, but they have free wireless access, so I might as well make a blog post while I'm here. ;-)

Did you know the following is not valid XHTML?


<form action="index.php">
    <input type="hidden" name="foo" value="bar" />
</form>

It appears that an input tag is not allowed to appear directly within a form tag. See detailed information here and note that <input> is not a valid child element of <form>. To be valid XHTML, the input tag must be wrapped by another block-level element, such as <p> or <fieldset>.

I can safely say I have always done this the wrong way. ;-) For example, the Solar_View_Helper_Form class puts all hidden fields at the top of the form, and all other fields in a <dl>...</dl> block. As a result, the hidden fields cause the page to be invalid (but the others are valid because they are wrapped properly).

Solution? Wrap the hidden fields in a <fieldset style="display: none">...</fieldset> tag. Now the page validates, and the hidden fieldset doesn't alter the page layout at all. This change has been committed and will be available in the next release of Solar.

(UPDATE: Fixed the link to the XHTML spec; thanks, David Rodger.)


Easy Benchmarking with Solar

Comparative benchmarking is tedious work. It's not hard to do, it's just no fun to set up the same scaffold every time you want to figure out how long it takes different pieces of code to execute.

To do a benchmark, essentially you need only four things: a timing mechanism, a loop to run the first case, a loop to run the second case, and a way to show the time taken by each loop.


$loopTimes = 1000;

$before = microtime(true);
for ($i = 0; $i < = $loopTimes; ++$i) {
    // case #1:
    // this code gets run $loopTimes
}
$after = microtime(true);
$case1 = $after - $before;

$before = microtime(true);
for ($i = 0; $i <= $loopTimes; ++$i) {
    // case #2:
    // this code gets run $loopTimes
}
$after = microtime(true);
$case2 = $after - $before;

echo "Case 1 ran $loopTimes in $case1 seconds";
echo "Case 2 ran $loopTimes in $case2 seconds";

This is boring, and repetitive, and essentially the same every time (except for the code cases being benchmarked). This makes it a classic candidate for refactoring to a PHP class.

Enter Solar_Test_Bench. As with Solar_Test, you extend the base class, add your own code cases as bench*() methods, and a runner will execute each of those methods the same number of times and display how long each one took. (It uses Solar_Debug_Timer for the timing mechanism.)

Here's an example of a real benchmark test from Solar to test the speed difference between require_once() and Solar::loadClass().


Solar::loadClass('Solar_Test_Bench');
class Bench_Solar_LoadClass extends Solar_Test_Bench {

    public $file = 'Solar/Sql.php';
    public $class = 'Solar_Sql';

    public function benchLoadClass()
    {
        Solar::loadClass($this->class);
    }

    public function benchRequireOnce()
    {
        require_once $this->file;
    }
}

To run it, we call the benchmark runner to execute each method in the class 1000 times, and get this output:


bash-2.05$ php bench.php Solar_FileExists 1000
name             : diff     : total
__start          : 0.000000 : 0.000000
benchLoadClass   : 0.005793 : 0.005793
benchRequireOnce : 0.034572 : 0.040365
__stop           : 0.000012 : 0.040377
bash-2.05$

You would want to run it a few times to get a better idea of the real speed, but the above is a representative result from my MacBook 2.0GHz. Looking at the "diff" column we can see that Solar::loadClass() is about 5 times faster than using require_once(). (Thanks to Clay Loveless for thinking up this particular benchmark.)

Here's another one:

Currently, Solar::fileExists() uses an fopen() call to see if a file exists on the include_path. (The regular file_exists() and is_readable() PHP calls do not check the include path.) However, Clay Loveless wondered if it would be faster to explode() the include_path and see if the file_exists() on each of those individually.

I won't copy the benchmarking class here; you can see it at Bench_Solar_FileExists. We actually test three different cases; the current fopen() case, and two new versions of using include_path. The results are:


bash-2.05$ php bench.php Solar_LoadClass 1000
name                   : diff     : total
__start                : 0.000000 : 0.000000
benchFopen             : 0.040105 : 0.040105
benchExplodeInclPath   : 0.015582 : 0.055687
benchNoExplodeInclPath : 0.020612 : 0.076299
__stop                 : 0.000004 : 0.076303
bash-2.05$

So the second case, where we explode() the include_path and then check file_exists() on each of the resulting paths, is about 3 times faster than using fopen(). The next release of Solar will use that code instead of the current fopen() code as a result.

(Note: the benchmarking classes are in Subversion only at this point, but will be in the next release of Solar when it comes out.)


Dependency Injection in Solar

Jeff Moore talks about dependency injection in PHP and opines as to how he'd like to see "the current crop of frameworks" adopt the technique. Jeff, your wish is granted! (At least for Solar. ;-)

Because it makes great use of dependecy injection, Solar has a standardized form of generating/retrieving dependency objects using its Solar::dependency() method.

The calling code sends the dependency params to the target object at construction time. The target object then passes those params through Solar::dependency() to retrieve or create the dependency object.

The params may be an object (the dependency object itself), or a string (treated as a registry key for Solar_Registry::get()), or an array (which are treated as params to create a new dependency object internally at the target using Solar::factory()).

UPDATE (2009-03-28): Updating documentation links.


Solar 0.20.0 released

Exactly one month after the last release, I have uploaded Solar version 0.20.0 alpha. There are lots of changes in this release, but the biggest news is that the page-controller now uses method-based actions (as opposed to file-based actions).

You can read the change notes here, but it's a really long list. If you want something a little more readable, with better narrative, you'll find it after the jump below. The new page-controller information is especially good. However, the narrative is quite long, so consider yourself warned. ;-)

Naming and Standards

About a third the change notes relate to naming, vocabulary, and standarization. Across the whole codebase, "drivers" are now called "adapters" in line with the Adapter design pattern. Similarly, I'm trying to use load() and is*() when appropriate, in line with the published coding standards.

Class Name Changes

Solar_User

The Solar_User subclasses have been brought to the top of the library, and their driver classes now have "Adapter" in their names.

  • Solar_User_Access => Solar_Access
  • Solar_User_Access_* => Solar_Access_Adapter_*
  • Solar_User_Auth => Solar_Auth
  • Solar_User_Auth_* => Solar_Auth_Adapter_*
  • Solar_User_Role => Solar_Role
  • Solar_User_Role_* => Solar_Role_*

Solar_Cache

The cache driver classes also now have "Adapter" in their name.

  • Solar_Cache_File => Solar_Cache_Adapter_File
  • Solar_Cache_Memcache => Solar_Cache_Adapter_Memcache

Solar_Sql

The SQL driver classes have been renamed to "Adapter" classes.

  • Solar_Sql_Driver_* => Solar_Sql_Adapter_*

Inherited Config File Values

I have modified Solar_Base so that it looks at the Solar.config.php values for all its parent classes, and inherits them for the current instance. Say for example you have this inheritance hierarchy:



<?php
    class Foo_Base extends Solar_Base {}

    class Foo_Bar extends Foo_Base {}

    class Foo_Bar_Baz extends Foo_Bar {}
?>

Let's also say you have this in your config file:


<?php
    $config['Foo_Base']['zim'] = 'dib';
?>

When you instantiate Foo_Bar_Baz, its $_config will receive array('zim' => 'dib') from the config file, even though there is no 'Foo_Bar_Baz' config file key. This is because Solar_Base now grabs all parent config-file values and merges them automatically into child class config-file values. So unless you override them specifically for the particular child class, the parent values will be used. Parent values are merged top-down, so the immediate parent value takes precedence over grandparent values.

Note that this does not mean that parent class $_config property values are merged when inherited. The inheritance only applies to the values in the config file.

Adapter Configuration

Any class that uses an adapter now passes configuration to that adapter via a 'config' config key entry. For example, it used to be that Solar_Sql took a 'driver' key and passed config to that driver like this:


<?php
    $config['Solar_Sql'] = array(
        'driver' => 'Solar_Sql_Driver_Mysql',
        'host'   => '127.0.0.1',
        'user'   => 'username',
        'pass'   => 'password',
        'name'   => 'database',
    );

?>

Now it uses an 'adapter' key and a 'config' key to indicate options passed to the underlying adapter object:


<?php
    $config['Solar_Sql'] = array(
        'adapter' => 'Solar_Sql_Adapter_Mysql',
        'config'  => array(
            'host'   => '127.0.0.1',
            'user'   => 'username',
            'pass'   => 'password',
            'name'   => 'database',
        ),
    );

?>

Note also that you can leave out the 'config' key entirely, and the master class will use the default configs for the adapter:


<?php
    $config['Solar_Sql'] = array(
        'adapter' => 'Solar_Sql_Adapter_Mysql',
    );

    $config['Solar_Sql_Adapter_Mysql'] = array(
        'host'   => '127.0.0.1',
        'user'   => 'username',
        'pass'   => 'password',
        'name'   => 'database',
    );

?>

Locale Files

It used to be that you could set the non-default location of a locale file using the 'locale' config key in in Solar_Base extended class. This is no longer the case. All locale files are always located in the "Locale/" directory in the class directory.

However, locale strings are now inherited; this means you can set locale keys in a parent class locale file, and the child class will use those values automatically (unless you override them in the child class locale file).

Page-Controller Class

Actions As Methods, Not Files

Previously, page actions were PHP files in the Actions/ directory (e.g., browse.action.php, read.action.php, etc). To map URIs to their actions, and to the parameters they needed, you used $_action_info with the action name as a key, and gave it a string of info paramters. For example, 'read' => 'id' would create $this->_info['id'] for you when the 'read' action was called.

In this release, actions are now methods in the page-controller class, and the parameters for that method are the info mapping. For example, the read action noted above would be "public method actionRead($id = null)". This makes the $_action_info mapping property unnecessary.

To migrate your action files to action methods, create one method for each file, and prefix its method name with the word "action". Then, for each $this->_info key you needed in your action, give the method a parameter. For example, if previously you had an "archive" action file, with info mappings for "year", "month", and "day", you could write a new action method like this:


<?php
public function actionArchive($year = null, $month = null, $day = null)
{
    // ...
}
?>

The page controller maps URI action names with dashes and underscores to studly caps; e.g., "/example-name/" and "/example_name/" become "/exampleName/" internally, which maps to the "actionExampleName()" method.

This also means that once you copy your action files into methods, you can delete the Actions/ directory entirely.

Views

Views are now stored in a singular-name directory, "View/", not a plural-name "Views/". This is in line with the rest of Solar, where directories have singular names.

Views used to be named ".view.php" for full view templates, and ".part.php" for partial view templates. This has changed; the new standard is to name all templates with just a ".php" suffix, and if you have a partial template, you should prefix its name with an underscore. This is identical to the Ruby on Rails convention.

For example, if previously you had "Views/template.view.php" and "Views/partial.part.php", you would rename them "View/template.php" and "View/_partial.php".

Additionally, the page controller defines a series of fallback view-template paths automatically. For a Vendor_App_Example class, the page controller will look first in Vendor/App/Example/View/ for Example-specific views, then Vendor/App/View for views used across all apps. This lets you use standard error views, standard comment views, etc. among all your applications without having to copy and paste them into each application.

The creation of Solar_View instances for view processing has been separated into its own method, _viewInstance(). If you need fine-grained control over how a view instance is created, you can override this method and the page controller will use the returned Solar_View object for rendering your views.

The _viewInstance() method also defines where helper classes are located for you. For a Vendor_App_Example class, it used to that you only got Vendor_App_Example_Helper_* helpers. In this release, the _viewInstance() method defines more locations for helper classes: Vendor_App_Example_Helper for Example-specific helpers, Vendor_App_Helper for helpers across all applications, and Vendor_View_Helper for helpers across the entire Vendor codebase. (Solar_View_Helper remains the final fallback.)

Layouts

Layouts are now stored in a singular-name directory, "Layout/", not a plural-name "Layouts/". This is in line with the rest of Solar, where directories have singular names.

Layouts used to be named ".layout.php" for full layout templates, and ".part.php" for partial layout templates. This has changed; the new standard is to name all templates with just a ".php" suffix, and if you have a partial template, you should prefix its name with an underscore. This is identical to the Ruby on Rails convention.

For example, if previously you had "Layouts/threeCol.layout.php" and "Layouts/auth.part.php", you would rename them "Layout/threeCol.php" and "Layout/_auth.php".

Additionally, the page controller defines a series of fallback layout-template paths automatically. For a Vendor_App_Example class, the page controller will look first in Vendor/App/Example/Layout/ for Example-specific layouts, then Vendor/App/Layout for layouts used across all apps. This lets you override generic layouts for your specific application.

The creation of Solar_View instances for layout processing has been separated into its own method, _layoutInstance(). If you need fine-grained control over how a layout instance is created, you can override this method and the page controller will use the returned Solar_View object for rendering your layouts.

The _layoutInstance() method also defines where helper classes are located for you. For a Vendor_App_Example class, it used to that you only got Vendor_App_Example_Helper_* helpers (which are specific to the Example app, not to layouts). In this release, the _layoutInstance() method defines two different locations for helper classes: Vendor_App_Helper for helpers across all applications, and Vendor_View_Helper for helpers across the entire Vendor codebase. (Solar_View_Helper remains the final fallback.)

Hooks

Previously, there were only three "hooks" in the page controller: _setup() for extended constructor code, _preAction() to run before the first action, and _postAction() to run after the last action (but before view rendering).

Those hooks have been extended and modified to become:

_setup()
after __construct()
_preRun()
before first action
_preAction()
before every action
_postAction()
after every action
_postRun()
after last action

Note that _preAction() and _postAction() have been repurposed; if you currently have code in those methods, you should move it to _preRun() and _postRun().

Finally, there is a separate _render() method that handes view and layout processing; if you need to pre- or post-process rendered output, override that method. For example:


<?php
protected function _render()
{
    $output = parent::_render();
    // run $output through filtering process, then return
    return $output;
}

?>


No More Loners!

Read and heed the latest from Clay Loveless: Stop Writing Loner Applications.

After nearly a decade in web application development, I continue to be dumbfounded by how many applications are built and released by the open-source community that apparently believe that they'll be the only complex, user-database application I'll will want to run.

...

In nearly every case, these loners have been built with no apparent concern for the fact that the person or company involved may already have a database of users, or that one of the other applications may be installed alongside it. Hard to believe, but true.

The result is that the guys in the trenches trying to put together a cohesive whole have to spend a great deal of their cycles writing and maintaining "bridge code" to allow site visitors to register and authenticate against all of the chosen applications at once. ...

Right on, Clay. Authentication and user-profile support in particular are a real burden to bear. I've tried very hard to make my apps (such as YaWiki) authentication-system agnostic, and the user-info related classes in Solar are read-only for exactly that reason.

One of the nice things about Solar-based authentication is that it is adapter based: you can change the backend from an LDAP server to an email server, or to a .htaccess file, and you never need to change your application code. (PEAR Auth also provides decent tools for this if you need PHP4 support.)

I have one other major criticism of most public code: classes are not generally namespaced properly. It's as if project managers think theirs is the only "User" or "Member" class in the world. All classes need, at a minimum, a project-name or vendor-name prefix. (Consistency in naming is a related issue, but I'll save that for another time.)

This is one thing the Zend Framework gets right, although it was against their will for a very long time. (All Zend classes are prefixed with "Zend_" so they automatically deconflict with all other userland classes.) That's one thing I'm glad I kept yammering about while I was at Zend; it took months to get the managers to accept that as a naming convention, and even then it was only through the combined efforts of numerous developers to push it through.


Quick Hits: Savant Forum, Akismet

Two quick hits: first, by popular request, I've started a web-forum for Savant at http://phpsavant.com/forum; it uses Vanilla. Second, because of a recent spate of spam attacks on my blog comments (1000 or more per day), I've activated Akismet; in 24 hours it has captured 3900 spam comments and trackbacks. Makes life a lot easier, although it'd be nice if that was the default spam-catcher for Wordpress.


Solar 0.19.0 released

(Solar, the simple object library and application repository for PHP5, is both a library and framework for developing web applications in PHP5.)

The single biggest change in this release is in the license; we have moved from LGPL to New BSD.

The main additions in this release are project-support related.

  • The Solar_Docs_Apiref class will read an entire Solar-style file hierarchy and parse the inline documentation into an array; you can then build a writer of your own to take that array and generate documentation files from it. (This is how I build the API reference documentation for the Solar web site.)
  • The related Solar_Docs_Phpdoc class will parse a PHPDoc comment block into its summary, narrative, and technical portions. While nowhere near as robust or full-featured as PHPDocumentor, I think the internals of Solar_Docs_Phpdoc are much easier to understand. It doesn't support inline tags, but most of the important block tags are recognized and parsed appropriately (@var, @param, @return, @throws, etc).
  • Solar_Docs_Apiref also makes use of the new Solar_Class_Map, which parses a Solar-style file hierarchy and returns an array of class-name keys with file-name values.
  • There is a new Solar_Log class, with adapters for file-based logging (good for production), echo-based logging (good for development), and multiple log support.

There's one big change in Solar_View: instead of custom helper locations being defined by paths, they are now defined by class names. This means your custom helpers no longer need to be named 'Solar_View_Helper_*'; you can now name them as is proper for their location in the file system. For example, if your helper classes are in the "Vendor/App/Helper/*" directory, you now name each helper class "Vendor_App_Helper_*". This makes helper class names consistent with the rest of Solar.

In line with this, you no longer use Solar_View::addHelperPath(),
getHelperPath(), or setHelperPath(); instead, you addHelperClass(),
getHelperClass(), and setHelperClass(). The class-based methods work
just the same as the path-based methods, except you specify class
name prefixes instead of path prefixes. For example, if you used to
"addHelperPath('Vendor/App/Helper')", you would now "addHelperClass
('Vendor_App_Helper')". Then helpers of that class will be used
before the Solar_View_Helper classes are used.

Also in line with this, the Solar_View 'helper_path' config key has
been renamed 'helper_class', and a new Solar_Controller_Page config
key 'helper_class' has been added so that page controllers know where
helpers are (this is to support view helpers attached to layouts).

Finally, Solar_Test_Suite usage has changed a bit. Instead of
setting a 'sub' key to specify that you want to run a sub-series of
class tests, you specify that same value when calling
Solar_Test_Suite::run($sub).

Future Plans

The next release will concentrate on feature requests, and (sorry!)
another class reorganization so as to be more consistent with pattern-
based names, and to reduce the depth of some parts of the hierarchy.

None of the reorganizational changes should require more than a
simple search-and-replace on the existing code base when complete.
For example, Solar_Sql_Driver will become Solar_Sql_Adapter,
Solar_Cache_File will become Solar_Cache_Adapter_File, and so on.

The User subclasses (Auth, Role, Access) will come to the top of the
hierarchy, so Solar_User_Auth will become Solar_Auth, and the
Solar_User_Auth_Driver files will become Solar_Auth_Adapter files.

There are other change ideas too; you can see those in the todo file
here.