home / blog / Lithium-0-9-9-99-Problems-But-a-Framework-Aint-One
## Lithium 0.9.9: 99 Problems But a Framework Ain't One

Wow, we haven't been _here_ in a little while. My, where has the time gone? With the summer, everything kind of slowed down, which these things tend to do. Myself and other members of the core team got busy with building new startups, and others got new jobs. Our project manager,[ Garrett](http://twitter.com/gwoo) has taken a product leadership position within [ SourceForge](https://sourceforge.net/), which is a relationship we've definitely come to appreciate. Expect to see more on that front in the future.

We also attended / organized a fair few [speaking events](http://dev.lithify.me/lithium/wiki/blog/workshops-meetups-conferences), which also kept us all busy the last few months. Anyway, all that is to say we've clearly gone way too long without a release. I'm pretty sure that won't happen again.

So yeah, sorry about that. My bad.

Turns out though, today is a very fortuitous day for a release. Not only did we celebrate the public debut of the project just two days ago (we announced prior to that, but the code/project site weren't public till Nov. 3rd), but today is also a day to [remember, remember](http://vforvendetta.warnerbros.com/).

A lot has happened in the past year, and especially since the last release. We've pushed even further forward toward being the de-facto framework for building high-quality apps with [less bloat](http://twitter.com/bobthecow/status/29493213516) [and  less](http://twitter.com/bobthecow/status/29494928076) [yak-shaving](http://sethgodin.typepad.com/seths_blog/2005/03/dont_shave_that.html), and it's starting to catch on.

### Launches

This past August saw the launch of the very first e-commerce site powered exclusively by MongoDB: [Totsy.com](http://www.totsy.com/), a high-traffic private sale site. What's more, that site was also exclusively built on Lithium. You can see a video case-study of [Totsy's CTO](https://twitter.com/mitchitized) talking about [his experience building this app on the Lithium + MongoDB stack](http://www.10gen.com/video/mongoboston2010/totsy).

On a more personally gratifying note, two weeks ago today, I got to be part of the most extraordinary conference for people who build stuff on the Web: [Brooklyn Beta](http://brooklynbeta.org/). Many, many others have already [written about it at length](http://www.google.com/search?q=Brooklyn+Beta), so I won't rehash the conference itself here. This event was a joint venture between [ Analog](http://analog.coop/) and [Fictive Kin](http://fictivekin.com/), and I have the utmost personal and professional respect for the guys in each. For that reason, I was thrilled to see them launch the betas for each of their products, [ Mapalong](https://mapalong.com/) and [Gimme Bar](https://gimmebar.com/), but more importantly because both are using Lithium!

It's very exciting to see both the hard work on the framework itself, and the hard work of people building great apps on it, finally coming to fruition. The feedback from these teams and many others has been integral in making Lithium what it is today. Thank you all.

### Release highlights

What this release has lacked in timeliness, it has definitely made up for in quality and depth. There have been almost 400 commits, from a record-setting 12 contributors. That's three times bigger than the last two releases, and almost as big as the last 4 releases combined (0.7 through 0.9.5).

While explaining every change wouldn't be practical, here's a short list of some of the highlights, with a focus on changes in the interaction with the core architecture.

- **`Filters::apply()`**: The `Filters` class, which implements Lithium's method filtering infrastructure has a new method for lazily applying filters to static classes that might not get loaded. For example, suppose you have a `Posts` model, and you want to log queries to it:

{{{
use app\models\Posts;
use lithium\analysis\Logger;

Posts::applyFilter("find", function($self, $params, $chain) {
    Logger::info(json_encode(array("posts" => $params)));
    return $chain->next($self, $params, $chain);
});
}}}

Because this filter is being applied in the bootstrap process, the `Posts` class will always be loaded, whether or not it is used in the request. Since this is inefficient, we've introduced a way to apply filters like these _lazily_:

{{{
use lithium\analysis\Logger;
use lithium\util\collection\Filters;

Filters::apply('app\models\Posts', 'find', function($self, $params, $chain) {
    Logger::info(json_encode(array("posts" => $params)));
    return $chain->next($self, $params, $chain);
});
}}}

This filter has the same effect as the one above, but because we're delegating it to the `Filters` class, the filter itself doesn't get applied immediately unless the `Posts` class is already loaded. Otherwise, the filter doesn't get applied at all until / unless `Posts::find()` is called.

- **`Object::_instance()` and `Libraries::instance()`**: Since the beginning, Lithium has had a convention around how to define dependencies between classes using the `$_classes` attribute, and being able to override those dependencies individually with the constructor. 

However, the process of instantiating dependencies was a bit awkward, since it required grabbing the class name from the `$_classes` array, and calling `new $class()`. The `_instance()` method, now available in `Object` and `StaticObject`, abstracts this away to a simple one-liner, wherein you simply pass the key name of the dependency, and any configuration parameters you'd like:

{{{
class Foo {

    protected $_classes = array("renderer" => "app\extensions\template\Custom");

    public function render() {
        $renderer = $this->_instance("renderer", array("path" => "views/"));
        // ...
    }
}
}}}

`Libraries::instance()` works very similarly, accepting a class type and name to locate a class like `Libraries::locate()`, and instantiating the found class with optional constructor parameters.

- **Content negotiation with `Request::accepts()`**: The `Request` object now supports content negotiation, by parsing the client's [HTTP Accept](http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html) header, and returns the most preferential content type that an application is able to serve, based on the types configured in the `Media` class.
- **`Model::update()` and `Model::remove()`**: The `Model` class has two new methods which allow operating on many documents or records at once.
- **MongoDB schema support**: This release also improves schema support for MongoDB. Not only is it easier to store native Mongo objects, but by using the `$_schema` property of your models to tell Lithium what fields types to expect, you can take Mongo IDs as string input, and they'll automatically be translated to proper Mongo ID objects in queries and updates.
- **API documentation**: In addition to more features, this release also includes much more API documentation, which will be published shortly on [the docs page](http://lithify.me/docs) served through a brand-new, redesigned [ li3_docs](http://dev.lithify.me/li3_docs).
- **Routing with HTTP meta-data**: Previously, routes could only match on patterns in the URL. No more. Now, all the properties of the `Request` object are fully exposed, right through the familiar `Router` API:

{{{
// Only allow POST requests to FooController::create():
Router::connect("/create", array("Foo::create", "http:method" => "POST"));

// Allow POST or PUT::
Router::connect("/update", array("Foo::update", "http:method" => array("POST", "PUT")));

// Only match if on the dev server:
Router::connect("/secret", array("Secret::index", "http:host" => "dev.application.com"));

// Only match if request is over HTTPS:
Router::connect("/admin", array("Foo::index", "env:https" => true));
}}}

I'd also like to highlight a few changes coming in the next release, thanks to the efforts of [Denis de Bernardy](http://twitter.com/ddebernardy), who completely re-implemented the UUID generator, significantly reducing code complexity and eliminating the need for cross-cutting data classes. This work paved the way for his subsequent efforts on core crypto support for better password security, and the soon-to-be-integrated support for transparent, framework-native CSRF protection.

In addition, he and several talented Japanese developers have each independently implemented support for PostgreSQL, which will also make its debut in the next release.

Finally the [TextMate plugin](http://dev.lithify.me/lithium_textmate) has one minor improvement: when it is added to your application, and you run your tests in a browser, file paths to errors or exceptions will render as links that will jump you to that file and line in TextMate. Check it out if you're a Mac user.


### API changes

It's hard to have a release this big without a few backwards-compatibility breaks, fortunately all ours are minor and easily fixed:

- In `app/config/bootstrap/libraries.php`, add a new require statement: `require LITHIUM_LIBRARY_PATH . '/lithium/net/Message.php';`  just prior to the existing `require LITHIUM_LIBRARY_PATH . '/lithium/net/http/Message.php';` line.
- Calling `$this->render('foo')` in a controller action no longer works. Instead, these calls should be changed to `$this->render(array('template' => 'foo'))`.
- `Inflector::camelize()` now replaces both "_" and "-" characters in a string (previously it only replaced "_").
- If you're using a custom port in a database configuration, the `"port"` key is no longer supported. Instead, change the format of the value of your `"host"` key to `"host:port"`.
- If you use `Model::_connection()` to make direct calls to your backend from inside your models, please note that this method has been deprecated. You can use the new public implementation, `Model::connection()`.
- If you use Lithium's G11n infrastructure, please note two important changes in `Catalog`'s API: the first parameter of both the `read()` and `write()` methods are now the name of the configuration you wish to interact with. In the case of `read()`, you can pass `true` as the first parameter to read from any/all, which is the same effect as the previous implementation.

For an easy migration, simply change all `read()` calls from `Catalog::read(...)` to `Catalog::read(true, ...)`.

The replacement for `write()` calls is equally straightforward but slightly harder to automate: where calls previously looked like this: `Catalog::write('message', 'en', $data, array('name' => 'runtime'))`, they're now like this: `Catalog::write('runtime', 'message', 'en', $data)`.

### What's next?

With this release out the door, the team is very excited to move on to what's next. We have just two major features left to implement before shipping a stable API, and we have several great plugins we're getting ready to release as well. We've also received lots of questions lately about providing a mailing list or forum for the community. People have also expressed difficulty in finding a central reference point for all things Lithium, like blog posts, podcasts, video and presentations. Well, we hear you. Stay tuned for an announcement on that front next week.

Till then, remember, remember the 5th of November!

~ nate ~

<br />

- [Download the new release](http://dev.lithify.me/lithium/versions)
- [See the full change log](http://dev.lithify.me/lithium/wiki/releases/0_9_9)