the solar framework for php 5 (2010 confoo)

65
Solar for PHP 5 The Best Framework You’ve Never Heard Of Paul M. Jones ConFoo, Montréal 11 Mar 2010 http://joind.in/1350

Upload: pmjones88

Post on 25-Dec-2014

6.460 views

Category:

Technology


6 download

DESCRIPTION

This presentation is a whirlwind tour of the Solar framework for PHP 5. After a short bit of background, the presentation will outline the major concepts in Solar: everything is a library, the unified constructor, unified configuration, inherited configuration and localization, unified factory and adapter systems, lazy-loading registry, and the dependency-injection system. Next is an overview of how the dynamic dispatch cycle works in Solar, and how it compares to other framework dispatch cycles. From there we will move on to the SQL system, including the MysqlReplicated adapter, and lead into the ORM system. The ORM overview will briefly cover models, collections, records, automated filters, automated form generation, and more. After discussing the authentication layer, CLI tooling, and command-line controllers, it will wrap up with a brief discussion of Solar project architecture, and a short note on Solar's performance in relation to other popular frameworks.

TRANSCRIPT

Page 1: The Solar Framework for PHP 5 (2010 Confoo)

Solar for PHP 5The Best Framework You’ve Never Heard Of

Paul M. JonesConFoo, Montréal

11 Mar 2010

http://joind.in/1350

Page 2: The Solar Framework for PHP 5 (2010 Confoo)

Read This

Page 3: The Solar Framework for PHP 5 (2010 Confoo)

About Me• Web Architect

• PHP since 1999 (PHP 3)

• Savant Template System (phpsavant.com)

• PEAR: DB_Table, Text_Wiki

• PEAR Group (2007-2008)

• Zend Framework

• Web framework benchmarks

Page 4: The Solar Framework for PHP 5 (2010 Confoo)

“Another Framework?”

• http://solarphp.com

• The first E_STRICT framework for PHP 5

• Pre-dates Zend Framework

• Portions of ZF based on early Solar work(DB, DB_Select, DB_Table/Row/Rowset, View, View_Helper, and others)

• Built to be configurable, adaptable, scalable

Page 5: The Solar Framework for PHP 5 (2010 Confoo)

Library/Framework Progression

Solar

Cake, Symfony

ZendFramework

Lithium

Lib FW

PEAR

PhpClasses

Page 6: The Solar Framework for PHP 5 (2010 Confoo)

Overview

• Foundational concepts and techniques

• Dispatch cycle

• Package highlights

• Project architecture

• Performance indicators

Page 7: The Solar Framework for PHP 5 (2010 Confoo)

Foundations

Page 8: The Solar Framework for PHP 5 (2010 Confoo)

<?php class Vendor_Foo_Bar {  // Vendor/Foo/Bar.php}

PEAR Standards

• pear.php.net

• 10 years of public usage and vetting

• Coding style guide

• Vendor- or name-spaces

• Class-to-file naming convention

Page 9: The Solar Framework for PHP 5 (2010 Confoo)

Class-to-File Effects• Consistent and predictable

(autoloader)

• Low cognitive friction on structure and organization

• Adaptable to change and integration

• Support files in parallel

• Works in every project

Page 10: The Solar Framework for PHP 5 (2010 Confoo)

Techniques

• Unified constructor

• Unified configuration

• Unified factory

• Lazy-loading registry

• Dependency management

Page 11: The Solar Framework for PHP 5 (2010 Confoo)

class Foo {  protected $_foo;  public function __construct($foo = null)  {    $this->_foo = $foo;  }}

Typical Constructor

Page 12: The Solar Framework for PHP 5 (2010 Confoo)

class Bar extends Foo {  protected $_bar;  protected $_baz;  public function __construct($foo = null, $bar = "dib", $baz = "gir")  {    parent::__construct($foo)    $this->_bar = $bar;    $this->_baz = $baz;  }}

Typical Constructor

Page 13: The Solar Framework for PHP 5 (2010 Confoo)

class Vendor_Foo {    protected $_default = array("foo" => null);    protected $_foo;    public function __construct($config = array()) {    $config = array_merge($this->_default, $config);    $this->_foo = $config["foo"];  }}

Unified Constructor

Page 14: The Solar Framework for PHP 5 (2010 Confoo)

webhost                  = www.example.comdatabase.adapter         = pdo_mysqldatabase.params.host     = db.example.comdatabase.params.username = dbuserdatabase.params.password = secretdatabase.params.dbname   = dbname

# what class uses them?# what if different classes use "database" as their key?

Typical Config File

Page 15: The Solar Framework for PHP 5 (2010 Confoo)

<!-- /path/to/config.php --><?php$config = array();$config["Solar_Sql"] = array(  "adapter" => "Solar_Sql_Adapter_Mysql",  "host"    => "db.example.com",  "user"    => "dbuser",  "pass"    => "secret",  "name"    => "dbname",);

return $config;?>

<!-- capture return value from include --><?php $array = include "/path/to/config.php"; ?>

Solar Config File

Page 16: The Solar Framework for PHP 5 (2010 Confoo)

$config = array(  "Vendor_Foo" => array(    "foo" => "zim",  ),);

// default values from config file$foo = new Vendor_Foo();

// instance-time values$foo = new Vendor_Foo(array(    'foo' => 'irk',));

Unified Configuration• Given unique class names, and unified constructor ...

• ... configuration keys map directly to class names ...

• ... unified configuration mechanism for all classes.

Page 17: The Solar Framework for PHP 5 (2010 Confoo)

class Vendor_Foo extends Solar_Base {  protected $_Vendor_Foo = array("foo" => null);}

class Vendor_Bar extends Vendor_Foo {  protected $_Vendor_Bar = array(

"bar" => "dib", "baz" => "gir",);

}

// Vendor_Bar will magically have all the default// config values of Vendor_Foo

Config Inheritance

Page 18: The Solar Framework for PHP 5 (2010 Confoo)

// typical adapter pattern for a new instance$db = DB::getAdapter("mysql"); // DB_Adapter_Mysql

// or by pre-configured singleton$db = DB::getInstance(); // DB_Adapter_Mysql

Typical Adapter Pattern• Typical adapter instantiation makes it difficult to apply

automatic configuration

• Different instantiation (static method instead of new)

• You need to remember if its an adapter or not

• Class limited

Page 19: The Solar Framework for PHP 5 (2010 Confoo)

// non-adapter$bar = Solar::factory("Vendor_Bar"); // Vendor_Bar

// adapter: assume that the config file has set the value ...// $config["Solar_Sql"]["adapter"] = "Solar_Sql_Adapter_Sqlite";$sql = Solar::factory("Solar_Sql"); // Solar_Sql_Adapter_Sqlite"

// factory a new instance with instance-time config$sql_other = Solar::factory("Solar_Sql", array(  "adapter" => "Solar_Sql_Adapter_Mysql",));

Unified Factory• Solar::factory() intercepts and recognizes

adapter calls

Page 20: The Solar Framework for PHP 5 (2010 Confoo)

// populate registry entries$db = new DB::factory('mysql');Registry::set('db', $db);

// later, elsewhere$db = Registry::get('db');

Typical Registry

Page 21: The Solar Framework for PHP 5 (2010 Confoo)

// lazy, using default adapter and configs.Solar_Registry::set("sql", "Solar_Sql");

// lazy, via config file$config["Solar"]["registry_set"]["sql"] = "Solar_Sql";

// instantiation$sql = Solar_Registry::get("sql");

Lazy-Loading Registry

Page 22: The Solar Framework for PHP 5 (2010 Confoo)

// typical dependency creationpublic function __construct() {  $this->db = DB::getAdapter();}

Dependency Management

• How to maintain dependencies on other objects?

• How to configure, replace, or test the other object?

• “Dependency injection” or “service locator”

Page 23: The Solar Framework for PHP 5 (2010 Confoo)

// constructor-based dependency injection.// $db = DB::getAdapter();// $foo = new Foo($db);public function __construct($db) {  $this->db = $db;}

// setter-based dependency injection.// $foo = new Foo();// $db = DB::getAdapter();// $foo->setDb($db);public function setDb($db) {  $this->db = $db;}

Dependency Injection

Page 24: The Solar Framework for PHP 5 (2010 Confoo)

// static locator.// $db = DB::getAdapter();// Locator::set("db", $db);public function __construct() {  $this->db = Locator::get("db");}

// instance locator as dependency injection.// $locator = new Locator();// $db = DB::getAdapter();// $locator->set("db", $db);// $foo = new Foo($locator);public function __construct($locator) {  $this->db = $locator->get("db");}

Service Locator

Page 25: The Solar Framework for PHP 5 (2010 Confoo)

Solar::dependency($class_hint, $specification);

Solar::dependency()

• Combined service locator and dependency injector

• Uses a registry key (which may be lazy-loaded) ...

• ... or a directly-passed dependency object ...

• ... or creates the dependency object internally.

Page 26: The Solar Framework for PHP 5 (2010 Confoo)

class Vendor_Foo extends Solar_Base {  public function _postConstruct() { parent::_postConstruct();    $this->_sql = Solar::dependency(      "Solar_Sql",      $this->_config["sql"]    );  }}

// inject an object$sql = Solar::factory("Solar_Sql");$foo = Solar::factory("Vendor_Foo", array("sql" => $sql));

// locate via registry key "sql"Solar_Registry::set("sql", "Solar_Sql");$foo = Solar::factory("Vendor_Foo", array("sql" => "sql"));

// create instance inside the target$foo = Solar::factory("Vendor_Foo", array("sql" => null));

Solar::dependency()

Page 27: The Solar Framework for PHP 5 (2010 Confoo)

<!-- /path/to/config.php --><?php// lazy-load Solar_Sql instance as "sql" $config["Solar"]["registry_set"]["sql"] = "Solar_Sql";

// use "sql" registry key for Vendor_Foo dependency$config["Vendor_Foo"]["sql"] => "sql";?>

<!-- script file --><?php// now Vendor_Foo locates the "sql" entry automatically$foo = Solar::factory("Vendor_Foo");

Dependency Config

Page 28: The Solar Framework for PHP 5 (2010 Confoo)

Dynamic Dispatch Cycle

Page 29: The Solar Framework for PHP 5 (2010 Confoo)

Web Server + PHPFramework

Boot Front Page Action View

Page 30: The Solar Framework for PHP 5 (2010 Confoo)

$system = dirname(dirname(__FILE__));set_include_path("$system/include");

require "Solar.php";

$config = "$system/config.php";Solar::start($config);

$front = Solar_Registry::get("controller_front");$front->display();

Solar::stop();

Bootstrap

Page 31: The Solar Framework for PHP 5 (2010 Confoo)

Web App Controllers

• Independent front and page controllers

• URIs always in format of /controller/action/param/param/param

• Front controller determines only the page controller class, not the action or params

Page 32: The Solar Framework for PHP 5 (2010 Confoo)

Front Controller

• Stack of class prefixes, e.g. Vendor_App

• /foo/bar/baz => Vendor_App_Foo

• Multiple prefixes? Uses first one.

Page 33: The Solar Framework for PHP 5 (2010 Confoo)

$config["Solar_Controller_Front"]["replace"] = array(  "{:alnum}" => "([a-zA-Z0-9]+)",);$config["Solar_Controller_Front"]["rewrite"] = array(  "page/{:alnum}/edit" => "page/edit/$1",);

$config["Solar_Controller_Front"]["routing"] = array(  "page" => "Other_App_Zim",);

Front Controller• Dynamic rewriter

• Static routing

Page 34: The Solar Framework for PHP 5 (2010 Confoo)

<?php$config["Solar_Controller_Front"]["rewrite"]["edit-page"] = array(    'pattern' => 'page/{:id}/edit',    'rewrite' => 'page/edit/$1',    'replace' => array(        '{:id}' => '(\d+)',    ),    'default' => array(        '{:id}' => 88,    ););

// then in a view:echo $this->namedAction('edit-page', array('id' => 70));

Front Controller

• Named actions

Page 35: The Solar Framework for PHP 5 (2010 Confoo)

Page Controller

• Looks at remaining portion of URI path and picks action

• /foo/bar/baz => Vendor_App_Foo

• public function actionBar($param)

• preRun(), preAction(), postAction(), postRun(), preRender(), postRender()

Page 36: The Solar Framework for PHP 5 (2010 Confoo)

framework/          # librariesapplication/           # separate include path  controllers/    FooController.php  # actions "bar" and "dib"    ZimController.php  # extends Foo  views/    foo/      bar.php      dib.php    zim/      bar.php      dib.php  layouts/    default.php  public/

Typical Page and View

Page 37: The Solar Framework for PHP 5 (2010 Confoo)

Solar/               # librariesVendor/              # same include path  App/    Foo.php          # actions "bar" and "dib"    Foo/      Layout/        default.php      Public/      View/        bar.php        dib.php    Zim.php          # extends Foo    Zim/      View/          # inherits Foo views        dib.php      # override view

Solar Page And View

Page 38: The Solar Framework for PHP 5 (2010 Confoo)

Package Highlights

Page 39: The Solar Framework for PHP 5 (2010 Confoo)

• SQL adapters

• ORM system

• Form generation

• CLI tooling

• Auth, Role, Access

Page 40: The Solar Framework for PHP 5 (2010 Confoo)

SQL Adapters

• Adapters for Mysql, Pgsql, Sqlite, Sqlite2, Oracle ... Mssql forthcoming

• PDO-based, multiple fetch*() styles

• Standardized insert(), update(), delete()

• Abstracted LIMIT, column types, table creation, index creation, sequences, auto-increment, column description, index description

Page 41: The Solar Framework for PHP 5 (2010 Confoo)

$sql = Solar::factory("Solar_Sql");

$stmt = "SELECT * FROM students WHERE name = :name";

$bind = array(  "name"  => "Bob'; DROP TABLE students;--",);

$list = $sql->fetchAll($stmt, $bind);

Prepared Statements

• Named placeholders and bound values

Page 42: The Solar Framework for PHP 5 (2010 Confoo)

$select = Solar::factory("Solar_Sql_Select");$select->from("table", array("col", "col", ...))       ->join()      // leftJoin(), innerJoin()       ->where("col = ?", $value)       ->group()       ->having()       ->union()     // unionAll()       ->order()       ->limit()     // page(), paging()       ->fetchAll(); // fetchOne(), fetchPairs(), etc

Query Builder

• Programmatically build complex SELECT statements

Page 43: The Solar Framework for PHP 5 (2010 Confoo)

$config["Solar_Sql_Adapter_MysqlReplicated"] = array(  "host" => "master.db.example.com",  ...  "slaves" => array(    0 => array("host" => "slave1.db.example.com"),    1 => array("host" => "slave2.db.example.com"),  ),);

MysqlReplicated• Adapter picks master or slave

• Switch to/from non-replicated with no code changes

• Automatic “gap” (GET-after-POST) management

Page 44: The Solar Framework for PHP 5 (2010 Confoo)

ORM System• TableDataGateway + DataMapper

Model objects

• Rowset Collection objects

• Row-and-relateds Record objects

• Relationship definition objects

• Catalog for model objects

• Uses underlying SQL layers

Page 45: The Solar Framework for PHP 5 (2010 Confoo)

class Vendor_Model_Invaders extends Solar_Sql_Model {  protected function _setup() {    $this->_table_name = "invaders"; // default        // reads columns from table, or can be stored in:    // $this->_table_cols = array(...);        // each record has these relateds:    $this->_belongsTo("irk");    $this->_hasOne("robot");    $this->_hasMany("weapons");    $this->_hasMany("invasions");    $this->_hasManyThrough("planets", "invasions");  }}

Model Setup

Page 46: The Solar Framework for PHP 5 (2010 Confoo)

'merge'          => merge data at 'server' (DB) or 'client'  (PHP)'native_by'      => 'wherein' or 'select' when matching natives'native_col'     => native col to match against foreign col'foreign_class'  => class name of the foreign model'foreign_alias'  => alias of the foreign table name'foreign_col'    => foreign col to match against the native col'cols'           => fetch these foreign cols'conditions'     => where or join-on conditions'foreign_key'    => magic shorthand for the foreign key col'order'          => how to order related rows

... plus fetch-time params and eager-fetch params.

Relationship Definitions

Page 47: The Solar Framework for PHP 5 (2010 Confoo)

$model = Solar_Registry::get("model_catalog");

$collection = $model->invaders->fetchAll(array(  "where"   => array("type = ?" => "short"),  "group"   => ...  "order"   => ...  "page"    => ...  "paging"  => ...  "eager"   => array("weapons", "robot", "planets"),  ...));

$array  = $model->invaders->fetchAllAsArray(array(...));

$record = $model->invaders->fetchOne(array(...));

Fetching

Page 48: The Solar Framework for PHP 5 (2010 Confoo)

$zim = $model->invaders->fetchOne(array(  "where" = array("name = ?" => "Zim")));

echo $zim->doom;$zim->enemy = "Dib";

foreach ($zim->weapons as $weapon) {  echo $weapon->name;}

$zim->weapons->appendNew(array("name" => "raygun"));

$zim->save();

Records

Page 49: The Solar Framework for PHP 5 (2010 Confoo)

<?phpclass Vendor_Model_Invaders extends Solar_Sql_Model_Record{  protected function _setup() {    // ...    $this->_addFilter("bar", "validateAlnum");    $this->_addFilter("foo", "validateInList", array(        "one", "two", "three",    ));    $this->_addFilter("baz", "validateCustomThing");  }}

Record Filters• Solar_Filter, Solar_Filter_Validate*, Solar_Filter_Sanitize*

as generally-available classes, not regular expressions

• Vendor_Model_* will use Vendor_Filter_* automatically

• Applied on $record->save() automatically

Page 50: The Solar Framework for PHP 5 (2010 Confoo)

$zim  = $model->invaders->fetch($id);$form = $zim->newForm(); // Solar_Form object

$view = Solar::factory("Solar_View");$html = $view->form()             ->auto($form)             ->addProcessGroup("save", "cancel");

echo $html;

// automatic CSRF protection

Form Generation

Page 51: The Solar Framework for PHP 5 (2010 Confoo)

Much More Model

• Single-table inheritance

• Calculated and virtual columns

• Auto serializing of columns (arrays)

• Auto XML structs (EAV)

• Auto creation of tables and indexes

• Auto count-pages at fetch time

• Auto caching and cache-versioning

Page 52: The Solar Framework for PHP 5 (2010 Confoo)

$ ./script/solar make-vendor Vendor

$ ./script/solar make-model Vendor_Model_Invaders

$ ./script/solar make-app Vendor_App_Zim --model-name=invaders

# make-docs, make-tests, run-tests, link-public, ...

CLI Tooling

Page 53: The Solar Framework for PHP 5 (2010 Confoo)

CLI Controllers

• Independent “console” (front) and “command” (page) controllers

• Direct output with _out(), _outln(), _err(), _errln()

• VT100 escape codes built in

• Vendor-specific invocation

• ./script/vendor command-name

Page 54: The Solar Framework for PHP 5 (2010 Confoo)

Auth, Role, Access

• Auth adapters (SQL, LDAP, email, etc.)

• Role adapters (File, SQL)

• Access adapters (File, SQL)

• User class is composed of these

Page 55: The Solar Framework for PHP 5 (2010 Confoo)

Project Architecture

Page 56: The Solar Framework for PHP 5 (2010 Confoo)

project-system/  config.php    # config file  config/       # config support  docroot/      # vhost document root    index.php   # bootstrap    public/     # copies or symlinks to public assets  include/      # symlinks to PHP files  script/       # command-line scripts  source/       # actual PHP and support files  sqlite/       # sqlite databases  tmp/          # sessions, logs, caches, etc

System Directories

Page 57: The Solar Framework for PHP 5 (2010 Confoo)

include/       # single include-path for PHP files  Solar/       # symlink to source/solar/Solar  Solar.php    # symlink to source/solar/Solar.php  Vendor/      # symlink to source/vendor/Vendor  some.php     # symlink to source/other/some.php  else.php     # symlink to source/other/else.php

source/        # all "real" files for a vendor  solar/       # solar files    config/    Solar.php    Solar/      ...  vendor/      # vendor files    Vendor/  other/       # random assortments of 3rd-party libs    some.php    else.php

Source vs. Include

Page 58: The Solar Framework for PHP 5 (2010 Confoo)

Performance Indicators

Page 59: The Solar Framework for PHP 5 (2010 Confoo)

Benchmarks

• Google “web framework benchmarks”

• Amazon EC2 “Large” instance

• Apache, mod_php 5.3.2, APC

• 10 concurrent users, session enabled

• 5 runs of 1 minute each, pre-warmed cache

Page 60: The Solar Framework for PHP 5 (2010 Confoo)

Results Table

framework | rel | avg------------------------ | -------- | --------baseline-html | 1.1644 | 5366.99baseline-php | 1.0000 | 4609.12lithium-0.6 | 0.0913 | 420.61solar-1.0.0 | 0.1178 | 543.15symfony-2.0.0alpha1 | 0.1351 | 622.88zend-1.10.2 | 0.0523 | 241.17solar-1.0.0-preload | 0.1619 | 746.30zend-1.10.2-min | 0.0832 | 383.30

Page 61: The Solar Framework for PHP 5 (2010 Confoo)

Results Graph

lithium 0.6solar-1.0.0

symfony-2.0.0alpha1zend-1.10.2

solar-1.0.0-preloadzend-min

0 200 400 600 800

Page 62: The Solar Framework for PHP 5 (2010 Confoo)

• Be suspicious of benchmarks

• Only one data-point in decision making

• Measures only what you test

Page 63: The Solar Framework for PHP 5 (2010 Confoo)

• Foundational concepts and techniques

• Dispatch cycle

• Package highlights

• Project architecture

• Performance indicators

Conclusion

Page 64: The Solar Framework for PHP 5 (2010 Confoo)

Solar is Stable!

Page 65: The Solar Framework for PHP 5 (2010 Confoo)

Thanks!

http://solarphp.com

http://joind.in/1350