A Framework for People
Who Hate Frameworks.
A movement in 3 parts

• Frameworks suck
• Everything you know is wrong
• Lithium tries to suck less
The first part.
Let’s get one thing out
of the way:
Lithium sucks.
But that’s okay.
Because your
framework sucks, too.
And yes, I mean:
Why?
(Besides the obvious attempt at being provocative)
Frameworks Suck

• Code you will never use.
• Complexity overhead.
• You didn’t write it.
Also,

Martin Fowler.
His name is the
biggest, so it’s his
      fault.
We’re not saying design patterns are bad.
Quite the opposite.
Lithium implements many design patterns.
The Problem™
Some patterns only treat the symptoms,
instead of the cause.
Some examples:
Object dependencies.
“The principle of separating configuration from use.”
Sucks.
function initialize(&$controller, $settings = array()) {
    /* ...[snip]... */

    $prefixes = Router::prefixes()...
Configuration.
Everyone does it differently.
Sometimes in the same framework.
Sometimes in the same class.
Sucks
function spam($emails) {

    $this->Email->replyTo = 'nigerian.prince@example.com';
    $this->Email->from = 'Desmo...
Dependency injection.
A good idea!
... or is it?
[variables changed to protect the innocent.]
                [... not really. It’s Symfony.]
Show that object who’s boss.
class User {
    function __construct($storage) {
        $this->storage = $storage;
    }
}
...
Of course, we want this to abstract this.

Frameworks adore abstractions.
DI Container to the rescue!
class Container {
    static protected $shared = array();
    // ...

    public function getMailer() {
        if (isset(...
But now you want an abstraction to manage
the DI container.


Duh.
So you create a “Service Container”.
class Container extends sfServiceContainer {
    static protected $shared = array();

    protected function getMailTransp...
Of course, we now want to abstract the
crap out of the Service Container.


Double duh.
So lets use a Builder to configure the
Services.
Yeah!
require_once '/PATH/TO/sfServiceContainerAutoloader.php';
sfServiceContainerAutoloader::register();

$sc = new sfSer...
And for good measure, have our configurations
for Service Containers in XML files.
So....
We have Dependency Injection.
Managed by a Service Container.
Parametrized with XML data.
And the whole thing confi...
Anyone see what’s wrong here?
The second part.
Everything
you know
is wrong.
The sun does not
revolve around OOP
                                           ...nevertheless,
                          ...
Dependency injection.
Dependency
Injection  =
class User {

    public function create() {
        $logger = new Logger();
        $logger->write('Creating a new user.....
class User {

    public $logger;

    public function create() {
        $this->logger->write('Creating a new user...');
...
Dependency Injection
• Fixes the problem of static dependencies
• Ignores the problem of static relationships
 • Same meth...
class Service extends lithiumcoreObject {

    protected $_classes = array(
        'request' => 'lithiumnethttpRequest',
...
Coupling should be in
proportion to domain
relevance.
The problem of

state.
If...
Configure::write('debug', 0);


  is evil,
$this->debug = 0;



  is the
of evil.
class Service {

    protected $_timeout = 30;

    public function send($method, $data = null, array $options = array()) ...
OO doesn’t make you
think (about state).
Design patterns.
ActiveRecord
                        Data Access Object

 Unit of Work
                              Dependency Injection
...
L E
FA
Design patterns
• Each pattern is only useful in a limited
  context

• Layering many design patterns on top of
  each oth...
Tools do not mean...




...you can build a house.
The third part.
Lithium tries to suck less.
Un-broken solutions.
Aspect-Oriented Design
• Separation of concerns
• Domain classes should not know or care about cross-
   cutting concerns
...
Functional Programming

• Only possible when functions are first-class
  citizens

• Referential transparency
• Function p...
Referential transparency is not...


 $this                date()


           $_*
Referential transparency is not...


 $this                date()


           $_*
These Are Not
Design Patterns.
Less Suck
• Draws on years of experience building web
  frameworks

• PHP 5.3+ only
• Doesn’t assume you’re stupid
Ways we suck less:
Consistency.
<?php

namespace applicationbar;

use lithiumutilString;
use lithiumutilCollection;

class Foo extends lithiumcoreObject {...
<?php

namespace applicationbar;

use lithiumutilString;
use lithiumutilCollection;

class Foo extends lithiumcoreObject {...
public function __construct(array $config = array())
<?php
    public function __construct(array $config = array())

names...
<?php
     <?php
namespace applicationbar;
     class Foo extends lithiumcoreObject {
use lithiumutilString;
use lithiumut...
<?php
     <?php
namespace applicationbar;
     class Foo extends lithiumcoreObject {
use lithiumutilString;
use lithiumut...
<?php

namespace applicationbar;   3
use lithiumutilString;
use lithiumutilCollection;
                                   ...
<?php

namespace applicationbar;



                                    4
use lithiumutilString;
use lithiumutilCollection...
<?php

namespace applicationbar;

use lithiumutilString;
use lithiumutilCollection;

class Foo extends lithiumcoreObject {...
<?php

namespace applicationbar;

use lithiumutilString;
use lithiumutilCollection;

class Foo extends lithiumcoreObject {...
$options = array()
Keeps parameter lists short
             &
Makes class APIs more extensible
$config = array()
Same idea. But...!
Modifies class / object state.
Adaptable

   Auth

  Cache

  Catalog

Connections

  Logger

  Session
use lithiumsecurityAuth;

Auth::config(array(
    'customer' => array(
        'adapter' => 'Form',
        'model'   => '...
use lithiumstorageCache;

Cache::config(array(
    'local' => array('adapter' => 'Apc'),
    'distributed' => array(
     ...
use lithiumdataConnections;

Connections::config(array(
    'old' => array(
        'type'      => 'database',
        'ad...
use lithiumstorageSession;

Session::config(array(
    'cookie' => array(
        'adapter' => 'Cookie',
        'expire' ...
Also fun:
use lithiumstorageSession;

Session::config(array(
    'default' => array(
        'adapter' => 'MyCustomAdapter',
       ...
Multiple environments?
use lithiumstorageCache;

Cache::config(array(
    'default' => array(
        'development' => array(
            'adapte...
Works identically for all adapters.
If you remember nothing
else about configuration
state...
Immutability.
Set it and forget it.
Speed.
Zoom!

• Use native extensions (PECL) whenever
  possible.

• Don’t like a class? Change it. At runtime.
• Profiled at eve...
Flexibility.
Lithium is the most
flexible framework.
Most class dependencies
are dynamic.
class Service extends lithiumcoreObject {

    protected $_classes = array(
        'request' => 'lithiumnethttpRequest',
...
The Filter System:
Aspect-Oriented Design
for PHP.
Example: Caching & Logging

    Caching


       Logging


              Post::find()
Example: Caching & Logging

    Caching


       Logging


              Post::find()
Example: Caching & Logging

    Caching


       Logging


              Post::find()
use lithiumanalysisLogger;

Post::applyFilter('find', function($self, $params, $chain) {
    // Generate the log message
 ...
Post                                                                                   Logger
       use lithiumanalysisLo...
What about Observer?

• Dependent on a centralized publish/
  subscribe system

• Extra layer of abstraction
• Fewer possi...
What about Observer?


• Filters are self-contained and attach
  directly to objects

• Direct and intuitive
Features: Everything is an adapter.
G11n (Globalization)
• CLDR
• Gettext
• PHP arrays
• Code
• Pecl/intl support on the way
Databases

• 1st-class support for document-oriented
  databases

• MongoDB & CouchDB: production ready
• Relational datab...
<?php

$post = Post::create(array(
    'title' => 'Forget the words and sing along',
    'body' => 'Everything you know is...
This works on...

• MongoDB
• CouchDB
• MySQL
• SQLite (almost)
Databases

• Adapter based. Plugin aware.
• Will ship with MySQL, SQLite, PostgreSQL &
  SQL Server.

• Query API
Integration with other
frameworks

• Easily load & use libraries from other
  frameworks:

  • Zend Framework, Solar, Symf...
/* add the trunk */
Libraries::add("Zend", array(
    "prefix" => "Zend_",
    "includePath" => '/htdocs/libraries/Zend/tr...
namespace appcontrollers;

use Zend_Mail_Storage_Pop3;

class EmailController extends lithiumactionController {

    publi...
This has been a presentation by:

Joël Perras (@jperras)
Nate Abele (@nateabele)


            Sucks. But check it out any...
Lithium: The Framework for People Who Hate Frameworks
Lithium: The Framework for People Who Hate Frameworks
Upcoming SlideShare
Loading in...5
×

Lithium: The Framework for People Who Hate Frameworks

33,503

Published on

This is the presentation was given at ConFoo on March 11th by Nate Abele and Joël Perras, and is an introduction to the architectural problems with other frameworks that Lithium was designed to address, and how it addresses them. It also introduces programming paradigms like functional and aspect-oriented programming which address issues that OOP doesn't account for.

Finally, the talk provides a quick overview of the innovative and unparalleled features that Lithium provides, including the data layer, which supports both relational and non-relational databases.

Published in: Technology
2 Comments
56 Likes
Statistics
Notes
No Downloads
Views
Total Views
33,503
On Slideshare
0
From Embeds
0
Number of Embeds
13
Actions
Shares
0
Downloads
0
Comments
2
Likes
56
Embeds 0
No embeds

No notes for slide

Lithium: The Framework for People Who Hate Frameworks

  1. 1. A Framework for People Who Hate Frameworks.
  2. 2. A movement in 3 parts • Frameworks suck • Everything you know is wrong • Lithium tries to suck less
  3. 3. The first part.
  4. 4. Let’s get one thing out of the way:
  5. 5. Lithium sucks.
  6. 6. But that’s okay.
  7. 7. Because your framework sucks, too.
  8. 8. And yes, I mean:
  9. 9. Why? (Besides the obvious attempt at being provocative)
  10. 10. Frameworks Suck • Code you will never use. • Complexity overhead. • You didn’t write it.
  11. 11. Also, Martin Fowler.
  12. 12. His name is the biggest, so it’s his fault.
  13. 13. We’re not saying design patterns are bad. Quite the opposite.
  14. 14. Lithium implements many design patterns.
  15. 15. The Problem™
  16. 16. Some patterns only treat the symptoms, instead of the cause.
  17. 17. Some examples:
  18. 18. Object dependencies. “The principle of separating configuration from use.”
  19. 19. Sucks. function initialize(&$controller, $settings = array()) { /* ...[snip]... */ $prefixes = Router::prefixes(); if (!empty($prefixes)) { foreach ($prefixes as $prefix) { /* ...[do something nasty to the global state]... */ } } if (Configure::read() > 0) { App::import('Debugger'); Debugger::checkSecurityKeys(); } } Sucks hard.
  20. 20. Configuration.
  21. 21. Everyone does it differently.
  22. 22. Sometimes in the same framework.
  23. 23. Sometimes in the same class.
  24. 24. Sucks function spam($emails) { $this->Email->replyTo = 'nigerian.prince@example.com'; $this->Email->from = 'Desmond Etete <nigerian.prince@example.com>'; $this->Email->template = 'mo_monies'; $this->Email->sendAs = 'annoying_html'; foreach ($emails as $email) { $this->Email->to = $email['address']; $this->Email->subject = "Good to you news I have {$email['name']}"; $this->Email->send(); } }
  25. 25. Dependency injection.
  26. 26. A good idea!
  27. 27. ... or is it?
  28. 28. [variables changed to protect the innocent.] [... not really. It’s Symfony.]
  29. 29. Show that object who’s boss. class User { function __construct($storage) { $this->storage = $storage; } } $storage = new SessionStorage('SESSION_ID'); $user = new User($storage);
  30. 30. Of course, we want this to abstract this. Frameworks adore abstractions.
  31. 31. DI Container to the rescue!
  32. 32. class Container { static protected $shared = array(); // ... public function getMailer() { if (isset(self::$shared['mailer'])) { return self::$shared['mailer']; } $class = $this->parameters['mailer.class']; $mailer = new $class(); $mailer->setDefaultTransport($this->getMailTransport()); return self::$shared['mailer'] = $mailer; } }
  33. 33. But now you want an abstraction to manage the DI container. Duh.
  34. 34. So you create a “Service Container”.
  35. 35. class Container extends sfServiceContainer { static protected $shared = array(); protected function getMailTransportService() { return new Zend_Mail_Transport_Smtp('smtp.gmail.com', array( 'auth' => 'login', 'username' => $this['mailer.username'], 'password' => $this['mailer.password'], 'ssl' => 'ssl', 'port' => 465, )); } }
  36. 36. Of course, we now want to abstract the crap out of the Service Container. Double duh.
  37. 37. So lets use a Builder to configure the Services.
  38. 38. Yeah! require_once '/PATH/TO/sfServiceContainerAutoloader.php'; sfServiceContainerAutoloader::register(); $sc = new sfServiceContainerBuilder(); $sc-> register('mail.transport', 'Zend_Mail_Transport_Smtp')-> addArgument('smtp.gmail.com')-> addArgument(array( 'auth' => 'login', 'username' => '%mailer.username%', 'password' => '%mailer.password%', 'ssl' => 'ssl', 'port' => 465, ))-> setShared(false) ; $sc-> register('mailer', '%mailer.class%')-> addMethodCall('setDefaultTransport', array(new sfServiceReference ('mail.transport'))) ;
  39. 39. And for good measure, have our configurations for Service Containers in XML files.
  40. 40. So.... We have Dependency Injection. Managed by a Service Container. Parametrized with XML data. And the whole thing configured by a Builder. ...to fix one problem.
  41. 41. Anyone see what’s wrong here?
  42. 42. The second part.
  43. 43. Everything you know is wrong.
  44. 44. The sun does not revolve around OOP ...nevertheless, it moves. Galileo facing the Roman Inquistion - Cristiano Banti (1857)
  45. 45. Dependency injection.
  46. 46. Dependency Injection =
  47. 47. class User { public function create() { $logger = new Logger(); $logger->write('Creating a new user...'); $this->_doSomeInitialization(); $this->_databaseConnection->doATransaction($this)->create(); $logger->write('Finished creating user'); } } $user = new User(); $user->create();
  48. 48. class User { public $logger; public function create() { $this->logger->write('Creating a new user...'); $this->_doSomeInitialization(); $this->_databaseConnection->doATransaction($this)->create(); $this->logger->write('Finished creating user'); } } $user = new User(); $user->logger = new Logger(); $user->create();
  49. 49. Dependency Injection • Fixes the problem of static dependencies • Ignores the problem of static relationships • Same methods called on injected classes • No way to introduce new relationships • Higher overhead, more boilerplate code
  50. 50. class Service extends lithiumcoreObject { protected $_classes = array( 'request' => 'lithiumnethttpRequest', 'response' => 'lithiumnethttpResponse', 'socket' => 'lithiumnetsocketContext' ); protected function _init() { $class = Libraries::locate('socket.util', $this->_classes['socket']); $this->_connection = new $class($this->_config); // ... } /* ...[snip]... */ public function send($method, $path = null, $data = null, array $options = array()) { /* ...[snip]... */ $response = $this->_connection->send($request, array('classes' => $this->_classes)); // ... } }
  51. 51. Coupling should be in proportion to domain relevance.
  52. 52. The problem of state.
  53. 53. If... Configure::write('debug', 0); is evil, $this->debug = 0; is the
  54. 54. of evil.
  55. 55. class Service { protected $_timeout = 30; public function send($method, $data = null, array $options = array()) { // WTF does this do? $this->_prepare(); $response = $this->_connection->send($request, array( 'timeout' => $this->_timeout )); // ... } }
  56. 56. OO doesn’t make you think (about state).
  57. 57. Design patterns.
  58. 58. ActiveRecord Data Access Object Unit of Work Dependency Injection Registry Front Controller MVC Value Object Data Mapper Service Layer
  59. 59. L E FA
  60. 60. Design patterns • Each pattern is only useful in a limited context • Layering many design patterns on top of each other often indicates poor design choices • Mis-application arises from trying to run before you can walk
  61. 61. Tools do not mean... ...you can build a house.
  62. 62. The third part.
  63. 63. Lithium tries to suck less.
  64. 64. Un-broken solutions.
  65. 65. Aspect-Oriented Design • Separation of concerns • Domain classes should not know or care about cross- cutting concerns • Examples: • Caching • Logging • Access Control, etc.
  66. 66. Functional Programming • Only possible when functions are first-class citizens • Referential transparency • Function purity
  67. 67. Referential transparency is not... $this date() $_*
  68. 68. Referential transparency is not... $this date() $_*
  69. 69. These Are Not Design Patterns.
  70. 70. Less Suck • Draws on years of experience building web frameworks • PHP 5.3+ only • Doesn’t assume you’re stupid
  71. 71. Ways we suck less:
  72. 72. Consistency.
  73. 73. <?php namespace applicationbar; use lithiumutilString; use lithiumutilCollection; class Foo extends lithiumcoreObject { protected $_classes = array( 'cache' => 'lithiumstorageCache', 'logger' => 'lithiumanalysisLogger' ); public function __construct(array $config = array()) { // ... } protected function _init() { // ... } } ?>
  74. 74. <?php namespace applicationbar; use lithiumutilString; use lithiumutilCollection; class Foo extends lithiumcoreObject { protected $_classes = array( 'cache' => 'lithiumstorageCache', 'logger' => 'lithiumanalysisLogger' ); public function __construct(array $config = array()) { // ... 1 } protected function _init() { // ... } } ?>
  75. 75. public function __construct(array $config = array()) <?php public function __construct(array $config = array()) namespace applicationbar; public function __construct(array $config = array()) use public function __construct(array $config = lithiumutilString; array()) use lithiumutilCollection; public function __construct(array $config = array()) class Foo extends lithiumcoreObject { public function __construct(array $config = array()) protected $_classes = array( public function'lithiumstorageCache', = 'cache' => __construct(array $config array()) 'logger' => 'lithiumanalysisLogger' public function __construct(array $config = ); array()) public function __construct(array $config = array()) { // ... } public function __construct(array $config = array()) protected function _init() { public function __construct(array $config = array()) // ... } public function __construct(array $config = array()) } public function __construct(array $config = array()) ?> public function __construct(array $config = array())
  76. 76. <?php <?php namespace applicationbar; class Foo extends lithiumcoreObject { use lithiumutilString; use lithiumutilCollection; protected function _init() { class Foo extends lithiumcoreObject { $or = $some->highOverHead($operation); $or()->otherwise(HARD_TO_TEST)->code(); protected $_classes = array( } 'cache' => 'lithiumstorageCache', } 'logger' => 'lithiumanalysisLogger' ); ?> public function __construct(array $config = array()) { // ... } protected function _init() { // ... 2 } } ?>
  77. 77. <?php <?php namespace applicationbar; class Foo extends lithiumcoreObject { use lithiumutilString; use lithiumutilCollection; protected function _init() { class Foo extends lithiumcoreObject { $or = $some->highOverHead($operation); $or()->otherwise(HARD_TO_TEST)->code(); protected $_classes = array( } 'cache' => 'lithiumstorageCache', } 'logger' => 'lithiumanalysisLogger' ); ?> public function __construct(array $config = array()) { // ... } protected function _init() { // ... 2 } } $foo = new Foo(array('init' => false)); ?>
  78. 78. <?php namespace applicationbar; 3 use lithiumutilString; use lithiumutilCollection; new applicationbarFoo(); // loads app/bar/Foo.php class Foo extends lithiumcoreObject { protected $_classes = array( 'cache' => 'lithiumstorageCache', 'logger' => 'lithiumanalysisLogger' ); public function __construct(array $config = array()) { // ... } protected function _init() { // ... } } ?>
  79. 79. <?php namespace applicationbar; 4 use lithiumutilString; use lithiumutilCollection; class Foo extends lithiumcoreObject { protected $_classes = array( 'cache' => 'lithiumstorageCache', 'logger' => 'lithiumanalysisLogger' ); public function __construct(array $config = array()) { // ... } protected function _init() { // ... } } ?>
  80. 80. <?php namespace applicationbar; use lithiumutilString; use lithiumutilCollection; class Foo extends lithiumcoreObject { protected $_classes = array( 'cache' => 'lithiumstorageCache', 'logger' => 'lithiumanalysisLogger' 5 ); public function __construct(array $config = array()) { // ... } protected function _init() { // ... = $this->_classes['cache']; $cache } $cache::write(__CLASS__, $this->_someGeneratedValue()); } } } ?> ?>
  81. 81. <?php namespace applicationbar; use lithiumutilString; use lithiumutilCollection; class Foo extends lithiumcoreObject { protected $_classes = array( 'cache' => 'lithiumstorageCache', 'logger' => 'lithiumanalysisLogger' 5 ); $foo = new Foo(array('classes' => array( public function __construct(array $config = array()) { 'cache' => 'applicationextensionsCache' // ... ))); } protected function _init() { // ... = $this->_classes['cache']; $cache } $cache::write(__CLASS__, $this->_someGeneratedValue()); } } } ?> ?>
  82. 82. $options = array()
  83. 83. Keeps parameter lists short & Makes class APIs more extensible
  84. 84. $config = array()
  85. 85. Same idea. But...! Modifies class / object state.
  86. 86. Adaptable Auth Cache Catalog Connections Logger Session
  87. 87. use lithiumsecurityAuth; Auth::config(array( 'customer' => array( 'adapter' => 'Form', 'model' => 'Customer', 'fields' => array('email', 'password') ) ));
  88. 88. use lithiumstorageCache; Cache::config(array( 'local' => array('adapter' => 'Apc'), 'distributed' => array( 'adapter' => 'Memcached', 'servers' => array('127.0.0.1', 11211), ), 'default' => array('adapter' => 'File') ));
  89. 89. use lithiumdataConnections; Connections::config(array( 'old' => array( 'type' => 'database', 'adapter' => 'MySql', 'user' => 'bobby_tables', 'password' => '******', 'database' => 'my_app' ), 'new' => array( 'type' => 'http', 'adapter' => 'CouchDb', 'database' => 'my_app' ) ));
  90. 90. use lithiumstorageSession; Session::config(array( 'cookie' => array( 'adapter' => 'Cookie', 'expire' => '+2 days' ), 'default' => array('adapter' => 'Php') ));
  91. 91. Also fun:
  92. 92. use lithiumstorageSession; Session::config(array( 'default' => array( 'adapter' => 'MyCustomAdapter', 'expires' => '+2 days', 'custom' => 'Whatevah!' ) )); public function __construct(array $config = array())
  93. 93. Multiple environments?
  94. 94. use lithiumstorageCache; Cache::config(array( 'default' => array( 'development' => array( 'adapter' => 'Apc' ), 'production' => array( 'adapter' => 'Memcached', 'servers' => array('127.0.0.1', 11211) ) ) ));
  95. 95. Works identically for all adapters.
  96. 96. If you remember nothing else about configuration state...
  97. 97. Immutability. Set it and forget it.
  98. 98. Speed.
  99. 99. Zoom! • Use native extensions (PECL) whenever possible. • Don’t like a class? Change it. At runtime. • Profiled at every step of the way.
  100. 100. Flexibility.
  101. 101. Lithium is the most flexible framework.
  102. 102. Most class dependencies are dynamic.
  103. 103. class Service extends lithiumcoreObject { protected $_classes = array( 'request' => 'lithiumnethttpRequest', 'response' => 'lithiumnethttpResponse', 'socket' => 'lithiumnetsocketContext' ); } $service = new Service(array('classes' => array( 'socket' => 'mycustomSocket' )));
  104. 104. The Filter System: Aspect-Oriented Design for PHP.
  105. 105. Example: Caching & Logging Caching Logging Post::find()
  106. 106. Example: Caching & Logging Caching Logging Post::find()
  107. 107. Example: Caching & Logging Caching Logging Post::find()
  108. 108. use lithiumanalysisLogger; Post::applyFilter('find', function($self, $params, $chain) { // Generate the log message $conditions = $params['options']['conditions']; $message = 'Post query with constraint ' . var_export($conditions, true); Logger::write('info', $message); return $chain->next($self, $params, $chain); });
  109. 109. Post Logger use lithiumanalysisLogger; Post::applyFilter('find', function($self, $params, $chain) { // Generate the log message $conditions = $params['options']['conditions']; $message = 'Post query with constraint ' . var_export($conditions, true); Logger::write('info', $message); return $chain->next($self, $params, $chain); });
  110. 110. What about Observer? • Dependent on a centralized publish/ subscribe system • Extra layer of abstraction • Fewer possibilities
  111. 111. What about Observer? • Filters are self-contained and attach directly to objects • Direct and intuitive
  112. 112. Features: Everything is an adapter.
  113. 113. G11n (Globalization) • CLDR • Gettext • PHP arrays • Code • Pecl/intl support on the way
  114. 114. Databases • 1st-class support for document-oriented databases • MongoDB & CouchDB: production ready • Relational databases coming soon
  115. 115. <?php $post = Post::create(array( 'title' => 'Forget the words and sing along', 'body' => 'Everything you know is wrong' )); $post->save(); $post = Post::find($id); ?> <h2><?=$post->title; ?></h2> <p><?=$post->body; ?></p>
  116. 116. This works on... • MongoDB • CouchDB • MySQL • SQLite (almost)
  117. 117. Databases • Adapter based. Plugin aware. • Will ship with MySQL, SQLite, PostgreSQL & SQL Server. • Query API
  118. 118. Integration with other frameworks • Easily load & use libraries from other frameworks: • Zend Framework, Solar, Symfony
  119. 119. /* add the trunk */ Libraries::add("Zend", array( "prefix" => "Zend_", "includePath" => '/htdocs/libraries/Zend/trunk/library', "bootstrap" => "Loader/Autoloader.php", "loader" => array("Zend_Loader_Autoloader", "autoload"), "transform" => function($class) { return str_replace("_", "/", $class) . ".php"; } )); // Note that 'path' can be dropped if trunk/library/Zend is placed // directly into your /libraries directory. /* add the incubator */ Libraries::add("Zend_Incubator", array( "prefix" => "Zend_", "includePath" => '/htdocs/libraries/Zend/incubator/library', "transform" => function($class) { return str_replace("_", "/", $class) . ".php"; } ));
  120. 120. namespace appcontrollers; use Zend_Mail_Storage_Pop3; class EmailController extends lithiumactionController { public function index() { $mail = new Zend_Mail_Storage_Pop3(array( 'host' => 'localhost', 'user' => 'test', 'password' => 'test' )); return compact('mail'); } }
  121. 121. This has been a presentation by: Joël Perras (@jperras) Nate Abele (@nateabele) Sucks. But check it out anyway.

×