The good news is that I’ve rolled the 0.10.0 release for Solar, the simple object library and application repository for PHP5.
The bad news is that it has a ton of changes, and that the release after this will also have large number of changes. This is “bad” in the sense that none of the current users (inluding me) wants to change existing code to comply with the new Solar stuff, but it’s “good” in that it prepares Solar for wider acceptance among professional developers.
Read on for a very long description of the changes, especially regarding the new MVC architecture.
Changes For v0.10.0
The most obvious change is in code formatting. I’m going from tabs to 4-spaces, per the PEAR coding standard (I see their point now). Similarly, the PHP commenting docblocks are now indented one extra space; using spaces as tabs helps with this greatly. The Solar coding standards docs will be updated to reflect this.
However, I’m breaking with the PEAR convention for public/protected naming. The PEAR rule on visibility hints in naming is mostly a holdover from the PHP4 days: only private methods and properties get an underscore prefix, while both protected and public methods get no prefix (this is because protecteds may be extended and made public). This was an attempt to stay consistent with PHP4 code, but in PHP5 I just don’t find it to be that great. Thus, from now on, both private and protected properties and methods in Solar will be named with an underscore prefix. For example, the protected $config property in Solar 0.9.0 and earlier is changing to $_config. (Public properties and methods still get no prefix.) Making protecteds into publics is hereby heretical. 😉
After some discussion, I have decided that using pattern-based names where possible is more appropriate than inventing a new vocabulary just for Solar; at least one person has pointed this out to me in the past (hi Travis!) and it took me a while to arrive at the same conclusions as he did.
As a result, the “Solar_Cell” class family has been renamed “Solar_Model”. Likewise, the Solar::object() method has been renamed to Solar::factory().
Less Dependence On include_path
You no longer have to have the Solar base directory in your include path; Solar now “finds itself” in the filesystem and automatically prefixes loadClass() requests with the proper directory name. This makes it easier to move between installations of Solar without having to update the include_path ini settings.
However, when you require() Solar the first time, you still need to know where it is, so there is still a little bit needed from you for boostrapping. Even with that, though, I think this is easier than setting .htaccess directives, or getting your hosting provider to change include_path for you in the ini.php file.
There is a new Controller family of classes: Solar_Controller_Front and Solar_Controller_Page. Their purpose should be obvious from their pattern names; they are a FrontController for routing between Solar applications, and PageController for page-based applications, respectively. Together, they form the basis of …
New MVC Architecture
This is going to be the biggest news in Solar, even though the MVC classes are only a small part of the code base. We have talked about this on the mailing list before: the Solar_App class for MVC, while really useful, has a number of shortcomings, and needs badly to be updated.
First, Solar_App was not as automated as it could have been. You had to specify local directories, talk to the view object directly when assigning variables, etc. In the new architecture, Solar apps extend Solar_Controller_Page, and are a great deal more automatic. The controller picks the right view for the action script automatically, but you can also tell the controller explicitly what view to use. Regardless, your action scripts only manipulate the controller properties, and these are assigned by the controller to the view automatically. This dramatically improves documentation as well.
Second, and more importantly, the “model” portions did not lend themselves to distribution and auto-configuration very well at all. For example, if you had a “Blog” model class in your application, it was just named “Blog.php”. The problem comes when someone else has a “Blog.php” model in a different application: the two names conflict. This makes sharing and distribution difficult, because there’s no automatic deconfliction or namespacing. In the same way, it’s difficult to have entries in Solar.config.php that automatically match up with the Blog class.
As a result, I have moved models entirely outside the Solar_App architecture. Your Solar-based classes should have their own top-level vendor directory anyway (this is part of the namespacing deconfliction), so any models for your Vendor_App classes should go in (e.g.) your Vendor_Model namespace. Under this architecture, VendorOne_Model_Blog and VendorTwo_Model_Blog class names don’t conflict, and you can specify separate configs for them in Solar.config.php by their class names.
I know that removing models from the app-specific architecture sounds unintuitive, but after considering the problem of name deconfliction and configuration namespacing for the past couple of months, this solution seems simple and straightforward when it comes to distributed applications that may wish to draw on each other’s models.
Therefore, with some renaming based on the new pattern vocbulary standards, we now have the following directory structure; basically, the old “controllers/” directory is now “Actions/”, the “models/” directory is replaced with a Models directory higher in the hierarchy, and the “helpers/” directory is removed completely (you can keep action helpers in an Actions/Helpers/ directory itself if you wish).
Solar/ App/ Bookmarks.php -- the page-based application controller Bookmarks/ Actions/ -- application actions edit.action.php tag.action.php user.action.php Locale/ -- locale strings fr_FR.php en_US.php Views/ -- views related to actions auth.php edit.view.php error.view.php footer.php header.php list.view.php rss.view.php
Finally, Solar_App applications now expect to be unified under a front controller. (This is the “Solar_Site” class we’ve talked about in the past.)
Thus, instead of having (e.g.) bookmarks.php and blog.php in your web directory, you will have only (e.g.) front.php, which will run the Solar_App_Bookmarks app for you when you browse to “front.php/bookmarks”. The front-controller code looks similar to the old app-based code:
require_once 'Solar.php'; Solar::start(); $front = Solar::factory('Solar_Controller_Front'); $front->display(); Solar::stop();
Under this, and with the new Solar_Controller_Page based applications, instead of browsing to …
… you can browse to this instead:
This way, your applications can all route between another using the front.php front controller.
These are changes I expect to make after the 0.10.0 release.
I’m going to start using exceptions more liberally throughout Solar. I’ve been using exceptions in other work, and I am finally convinced of their usefulness. Frankly, my use of Solar_Error has been mostly to generate script-stopping E_USER_ERROR trace dumps, and that’s exactly what exceptions do. I don’t think I’ll get rid of Solar_Error, as it’s useful for internal messaging if nothing else.
I’m also going to start using the TwoStepView pattern, where the page-based application controller only generates its specific output, and the front controller will generate the surrounding site layout. (Right now the application controller does both, using a header.php and footer.php for the surrounding site layout.) This should help with site-wide theming and application output sharing.
Move Some Solar::start() Code to Solar_Controller_Front
Right now, Solar::start() builds a number of shared objects for applications: an SQL connection, a User object (with automated authentication processing), and so on. Now that Solar has a real front controller, I’m starting to think those processes are more appropriate for starting up the application space, not the general Solar environment. As such, I’m going to experiment with moving them into a _setup() method in Solar_Controller_Front.
Move Shared Objects To A Registry
This one I’m not so sure about. Under the new pattern-based vocabulary, the Solar shared objects should probably be called a “registry”. This may entail an actual Solar_Registry class; at the very least, it will mean renaming Solar::shared() to Solar::registry() to retrieved shared objects, and perhaps adding new methods like register() and unregister() to manipulate the registry.