SlideShare a Scribd company logo
1 of 125
Download to read offline
LazyRecord
                 The Fast PHP ORM

                                       林佑安
                                    Yo-An Lin (c9s)
12年4月22⽇日星期⽇日
.metadata
                • 林佑安 (c9s)
                • 190 repo/projects on GitHub
                • Perl programming since 2008
                • PHP programming since last year
                • c, c++, javascript, obj-c, ruby, python,
                  haskell, java, c#,VB .NET ...


12年4月22⽇日星期⽇日
Why another PHP
                    ORM ?


12年4月22⽇日星期⽇日
PHP ORMs

                • Doctrine




12年4月22⽇日星期⽇日
PHP ORMs

                • Doctrine
                • Propel



12年4月22⽇日星期⽇日
PHP ORMs

                • Doctrine
                • Propel
                • Idiorm / Paris


12年4月22⽇日星期⽇日
Propel / Doctrine

                • Propel uses XML Schema file.




12年4月22⽇日星期⽇日
Propel / Doctrine

                • Propel uses XML Schema file.
                • Doctrine uses XML/YAML/Annotations.



12年4月22⽇日星期⽇日
Propel / Doctrine

                • Propel uses XML Schema file.
                • Doctrine uses XML/YAML/Annotations.
                • Slow & Fat.


12年4月22⽇日星期⽇日
Propel / Doctrine

                • Propel uses XML Schema file.
                • Doctrine uses XML/YAML/Annotations.
                • Slow & Fat.
                • Doctrine is too complicated.

12年4月22⽇日星期⽇日
Common characteristic



12年4月22⽇日星期⽇日
• XML for configuration file.
                • XML for schema file.
                • XML for everything.
                • Concepts are from Java, too complicated.

12年4月22⽇日星期⽇日
Propel XML
                runtime.conf


12年4月22⽇日星期⽇日
<?xml version="1.0"?>
            <config>
              <log>
                <ident>propel-bookstore</ident>
                <type>console</type>
                <level>7</level>
              </log>
              <propel>
                <datasources default="bookstore">
                  <datasource id="bookstore">
                    <adapter>sqlite</adapter>
                    <connection>
                      <classname>DebugPDO</classname>
                      <dsn>mysql:host=localhost;dbname=bookstore</dsn>
                      <user>testuser</user>
                      <password>password</password>
                      <options>
                        <option id="ATTR_PERSISTENT">false</option>
                      </options>
                      <attributes>
                        <option id="ATTR_EMULATE_PREPARES">true</option>
                      </attributes>
                      <settings>
                        <setting id="charset">utf8</setting>
                        <setting id="queries">
                          <query>set search_path myschema, public</query><!-- automatically set postgresql's search_path -->
                          <query>INSERT INTO BAR ('hey', 'there')</query><!-- execute some other query -->
                        </setting>
                      </settings>
                    </connection>
                    <slaves>
                     <connection>
                      <dsn>mysql:host=slave-server1; dbname=bookstore</dsn>
                     </connection>
                     <connection>
                      <dsn>mysql:host=slave-server2; dbname=bookstore</dsn>
                     </connection>
                    </slaves>
                  </datasource>
                </datasources>
                <debugpdo>
                  <logging>
                    <details>
                      <method>
                        <enabled>true</enabled>
                      </method>
                      <time>
                        <enabled>true</enabled>
                        <precision>3</precision>
                      </time>
                      <mem>
                        <enabled>true</enabled>
                        <precision>1</precision>
12年4月22⽇日星期⽇日         </mem>
<datasource id="bookstore">
                    <adapter>sqlite</adapter>
                    <connection>
                      <classname>DebugPDO</classname>
                      <dsn>mysql:host=localhost;dbname=bookstore</dsn>
                      <user>testuser</user>
                      <password>password</password>
                      <options>
                        <option id="ATTR_PERSISTENT">false</option>
                      </options>
                      <attributes>
                        <option id="ATTR_EMULATE_PREPARES">true</option>
                      </attributes>
                      <settings>
                        <setting id="charset">utf8</setting>
                        <setting id="queries">
                          <query>set search_path myschema, public</query><!-- automatically set postgresql's search_path -->
                          <query>INSERT INTO BAR ('hey', 'there')</query><!-- execute some other query -->
                        </setting>
                      </settings>
                    </connection>
                    <slaves>
                     <connection>
                      <dsn>mysql:host=slave-server1; dbname=bookstore</dsn>
                     </connection>
                     <connection>
                      <dsn>mysql:host=slave-server2; dbname=bookstore</dsn>
                     </connection>
                    </slaves>
                  </datasource>
                </datasources>
                <debugpdo>
                  <logging>
                    <details>
                      <method>
                        <enabled>true</enabled>
                      </method>
                      <time>
                        <enabled>true</enabled>
                        <precision>3</precision>
                      </time>
                      <mem>
                        <enabled>true</enabled>
                        <precision>1</precision>
                      </mem>
                    </details>
                  </logging>
                </debugpdo>
              </propel>
            </config>




12年4月22⽇日星期⽇日
12年4月22⽇日星期⽇日
It should be simpler



12年4月22⽇日星期⽇日
Inspirations

                • JiftyDBI / Perl
                • KiokuDB / Perl
                • ActiveRecord / Ruby
                • Propel / PHP

12年4月22⽇日星期⽇日
ActiveRecord Pattern



12年4月22⽇日星期⽇日
client = Client.find(10)

        client = Client.first

        Client.where("orders_count = ?", params[:orders])

        Client.where("created_at >= :start_date AND created_at <= :end_date",
            {:start_date => params[:start_date], :end_date => params[:end_date]})

        Client.order("created_at DESC")

        Client.limit(5).offset(30)




12年4月22⽇日星期⽇日
Object::Declare
    use Object::Declare ['MyApp::Column', 'MyApp::Param'];

    my %objects = declare {

    param foo =>
        !is global,
        is immutable,
        valid_values are qw( more values );

    column bar =>
        field1 is 'value',
        field2 is 'some_other_value',
        sub_params are param( is happy ), param ( is sad );

    };

    print $objects{foo}; # a MyApp::Param object
    print $objects{bar}; # a MyApp::Column object

    # Assuming that MyApp::Column::new simply blesses into a hash...
    print $objects{bar}{sub_params}[0]; # a MyApp::Param object
    print $objects{bar}{sub_params}[1]; # a MyApp::Param object
                                                                       Audrey Tang
                                                                          唐鳳
                                                                               2006
12年4月22⽇日星期⽇日
Jifty::DBI

                package Simple;
                use Jifty::DBI::Schema;
                use Jifty::DBI::Record schema {
                    column foo => type is 'text';
                    column bar => type is 'text';
                };




12年4月22⽇日星期⽇日
Jifty::DBI

        package TestApp::Model::Phone;
        use Jifty::DBI::Schema;
        use Jifty::DBI::Record schema {
            column user => references TestApp::Model::User by 'id',
                is mandatory;
            column type => ...;
            column value =>
                validator is sub { ... },
                default is sub { }
                ;
        };




12年4月22⽇日星期⽇日
Jifty


                Model Schema




12年4月22⽇日星期⽇日
Jifty


       Model Schema ⇛ Action




12年4月22⽇日星期⽇日
Jifty


     Model Schema ⇛ Action ⇛


                               CRUD


12年4月22⽇日星期⽇日
Jifty
                App::Model::Phone ☚ write once




12年4月22⽇日星期⽇日
Jifty
                     App::Model::Phone
                App::Model::PhoneCollection




12年4月22⽇日星期⽇日
Jifty
                     App::Model::Phone
                App::Model::PhoneCollection

                 App::Action::CreatePhone




12年4月22⽇日星期⽇日
Jifty
                     App::Model::Phone
                App::Model::PhoneCollection

                 App::Action::CreatePhone
                 App::Action::UpdatePhone




12年4月22⽇日星期⽇日
Jifty
                     App::Model::Phone
                App::Model::PhoneCollection

                 App::Action::CreatePhone
                 App::Action::UpdatePhone
                 App::Action::DeletePhone




12年4月22⽇日星期⽇日
Jifty
                         App::Model::Phone
                    App::Model::PhoneCollection

                      App::Action::CreatePhone
                      App::Action::UpdatePhone
                      App::Action::DeletePhone

                $phone->as_create_action()->render();


12年4月22⽇日星期⽇日
12年4月22⽇日星期⽇日
What we need
                •   Can use PHP closures for validation, default value,
                    completion ..etc.

                •   Everything should be lazy.

                •   Simple API

                •   No overdesign.

                •   Mixin schema

                •   CRUD generation.

                •   Front-end CRUD integration.




12年4月22⽇日星期⽇日
PHP 5.3 Characteristic
                •   APC is fast.

                •   json_encode / json_decode (file) are slower than
                    require a simple array from php source code.

                •   function is faster than class method.

                •   class method is slower than properties.

                •   magic method is slower than normal class method.

                •   array is faster than object.


12年4月22⽇日星期⽇日
$array[] vs array_push




                                  https://github.com/c9s/SimpleBench




12年4月22⽇日星期⽇日
Function calls




                     https://github.com/c9s/SimpleBench




12年4月22⽇日星期⽇日
PHP ORM v1



12年4月22⽇日星期⽇日
EteDB
                • Initialize model schema in runtime.
                • Schema is defined in Model (in
                  __constructor).
                • MySQL only.
                • dynamic class generator (using eval)
                • too slow.
12年4月22⽇日星期⽇日
PHP ORM v2



12年4月22⽇日星期⽇日
LazyRecord
                • Lazy schema
                  loader
                                      • SQL Generator
                • Lazy attribute        for MySQL,
                                        PgSQL, SQLite
                • Lazy class loader
                • Lazy connection     • SplClassLoader
                • Static class        • ... etc
                  generator


12年4月22⽇日星期⽇日
Based on SQLBuilder



12年4月22⽇日星期⽇日
SQLBuilder

                • A Simple SQL Generator.
                • Prevent Injection.
                • Migration generator. (index, alter table...etc)
                • Support SQLite, Pgsql, Mysql syntax.
                • Pure SQL or with named-parameters.

12年4月22⽇日星期⽇日
<?php
        $sqlbuilder = new SQLBuilderQueryBuilder( $driver );
        $sql = $sqlbuilder->table('authors')->insert([
            'name' => 'Mary',
            'address' => 'Paris',
        ])->build();




12年4月22⽇日星期⽇日
-- General syntax
    INSERT INTO authors ( name , address ) VALUES ( 'Name' , 'Address' );

    -- PgSQL
    INSERT INTO "Authors" ( "Name" , "Address" ) VALUES ( 'Name' , 'Address' );

    -- MySQL
    INSERT INTO `Authors` ( `Name` , `Address` ) VALUES ( 'Name' , 'Address' );

    -- PDO
    INSERT INTO authors ( name , address ) VALUES ( ? , ? );
    INSERT INTO authors ( name , address ) VALUES ( :name , :address );




12年4月22⽇日星期⽇日
<?php
           $sql = $builder->table('Member')->select('*')
               ->where()
                   ->equal( 'a' , 'bar' )    // a = 'bar'
                   ->notEqual( 'a' , 'bar' )    // a != 'bar'
                   ->is( 'a' , 'null' )        // a is null
                   ->isNot( 'a' , 'null' )     // a is not equal
                   ->greater( 'a' , '2011-01-01' );
                   ->greater( 'a' , ['date(2011-01-01)'] ); // do not escape
                       ->or()->less( 'a' , 123 )
                       ->and()->like( 'content' , '%content%' );
                   ->group()                   // and ( a = 123 or b != 123 )
                       ->is( 'a' , 123 )
                       ->isNot( 'b', 123 )
                   ->ungroup()
                   ->build();




12年4月22⽇日星期⽇日
Overview



12年4月22⽇日星期⽇日
Model Overview



12年4月22⽇日星期⽇日
<?php
                $author = new Author;
                $ret = $author->create([
                    'name' => "Deflator Test $i",
                    'country' => 'Tokyo',
                    'confirmed' => true,
                    'date' => new DateTime('2011-01-01 00:00:00'),
                ]);
                if( $ret->success ) {
                    echo "Created!";
                }




12年4月22⽇日星期⽇日
<?php
                $ret = $author->update(array( 'name' => 'Bar' ));
                if( $ret->success ) {
                    echo "Updated!";
                }
                else {
                    echo $ret; // __toString support
                }




12年4月22⽇日星期⽇日
<?php
          $record = Author::load(array( 'name' => 'Foo' ));

          // To find a record with primary key:
          $record = Author::load( 1 );

          // To update a record (static):
          $ret = Author::update( array(
                  'name' => 'Author'
             ))->where()
                  ->equal('id',3)
                  ->execute();




12年4月22⽇日星期⽇日
$author->toJson();
                $author->toArray();
                $author->toXml();
                $author->toYaml();




12年4月22⽇日星期⽇日
Collection Overview



12年4月22⽇日星期⽇日
Iterator



                    <?php
                    $authors = new AuthorCollection;
                    foreach( $authors as $author ) {
                        echo $author->name , "n"
                    }




12年4月22⽇日星期⽇日
SQLBuilder Mix-In


                   <?php
                       $names = new NameCollection;
                       $names->where()
                           ->equal('name','Foo')
                           ->groupBy('name','address');
                   ?>




12年4月22⽇日星期⽇日
Filter


           <?php
               $newCollection = $names->filter(function($item) {
                       // do something else
               })->filter(function($item) {
                       return $item->confirmed;
               });
           ?>




12年4月22⽇日星期⽇日
Each



                  <?php
                      $names->each(function($item) {
                          $item->update([ .... ]);
                      });
                  ?>




12年4月22⽇日星期⽇日
Collection Pager

                <?php
                    /* page 1, 10 per page */
                    $authors = new AuthorCollection;
                    $pager = $authors->pager(1,10);

                     $pager = $authors->pager();
                     $items = $pager->items();

                     $pager->next(); // next page
                ?>




                               Integrate with OFFSET & LIMIT


12年4月22⽇日星期⽇日
Relationship
                <?php
                // has many
                $address = $author->addresses->create([
                    'address' => 'farfaraway'
                ]);

                // create related address
                $author->addresses[] = [
                    'address' => 'Harvard'
                ];

                $addresses = $author->addresses->items();

                foreach( $author->addresses as $address ) {
                    echo $address->address , "n";
                }



12年4月22⽇日星期⽇日
Schema



12年4月22⽇日星期⽇日
Powered by
            CascadingAttribute.php


12年4月22⽇日星期⽇日
<?php
                use LazyRecordSchemaSchemaDeclare;

                class AddressSchema extends SchemaDeclare
                {
                    function schema()
                    {

                    }
                }




12年4月22⽇日星期⽇日
<?php
                use LazyRecordSchemaSchemaDeclare;

                class AddressSchema extends SchemaDeclare
                {
                    function schema()
                    {
                        $this->column('address')
                                ->varchar(128);
                    }
                }




12年4月22⽇日星期⽇日
<?php
                use LazyRecordSchemaSchemaDeclare;

                class AddressSchema extends SchemaDeclare
                {
                    function schema()
                    {
                        $this->column('address')
                                ->integer();
                    }
                }




12年4月22⽇日星期⽇日
<?php
                use LazyRecordSchemaSchemaDeclare;

                class AddressSchema extends SchemaDeclare
                {
                    function schema()
                    {
                        $this->column('address')
                                ->timestamp();
                    }
                }




12年4月22⽇日星期⽇日
Default value & builder



12年4月22⽇日星期⽇日
$this->column('name')
                        ->varchar(30)
                        ->default('Default');




12年4月22⽇日星期⽇日
$this->column('name')
                        ->varchar(30)
                        ->default( array('current_timestamp') );




12年4月22⽇日星期⽇日
$this->column('name')
                        ->varchar(30)
                        ->defaultBuilder(function() {
                                return date('c');
                        })




12年4月22⽇日星期⽇日
$this->column('name')
                        ->varchar(30)
                        ->default('Default')
                        ->default( array('current_timestamp') )
                        ->defaultBuilder(function() {
                                return date('c');
                        })




12年4月22⽇日星期⽇日
Validator



12年4月22⽇日星期⽇日
$this->column('name')
                                ->varchar(30)
                                ->validator('ValidatorClass')




12年4月22⽇日星期⽇日
$this->column('name')
                     ->varchar(30)
                     ->validator( array('ValidatorClass','method') )




12年4月22⽇日星期⽇日
$this->column('name')
                                ->varchar(30)
                                ->validator('function_name')




12年4月22⽇日星期⽇日
$this->column('name')
                                ->varchar(30)
                                ->validator(function($val) { .... })




12年4月22⽇日星期⽇日
Filter



12年4月22⽇日星期⽇日
$this->column('name')
                     ->varchar(30)
                     ->filter( function($val) {
                        return preg_replace('#word#','zz',$val);
                });




12年4月22⽇日星期⽇日
Deflator / Inflator



12年4月22⽇日星期⽇日
use LazyRecordSchemaSchemaDeclare;

                class NameSchema extends SchemaDeclare
                {
                    function schema()
                    {
                        $this->column('created_on')
                            ->date()
                            ->isa('DateTime')
                            ->deflator( function($val) {
                                if( is_a( $val, 'DateTime' ) )
                                     return $val->format('Y-m-d');
                                elseif( is_integer($val) ) {
                                     return strftime( '%Y-%m-%d' , $val );
                                }
                                return $val;
                            })
                            ->inflator( function($val) {
                                return new DateTime( $val );
                            });
                    }
                }




12年4月22⽇日星期⽇日
$name->created_on; // DateTime object
          $name->created_on->format('Y-m-d');



          $name->create([
              'created_on' => new DateTime;
          ]);




12年4月22⽇日星期⽇日
Mixin schema



12年4月22⽇日星期⽇日
$this->mixin('MetadataMixinSchema');
          $this->mixin('I18nMixinSchema');
          $this->mixin('CommentMinxSchema');




12年4月22⽇日星期⽇日
Multiple data source



12年4月22⽇日星期⽇日
database.yml
        data_sources:
          master:
            dsn: 'mysql:host=localhost;dbname=lazy_test'
            user: root
            pass: 123123




12年4月22⽇日星期⽇日
database.yml
        data_sources:
          master:
            dsn: 'mysql:host=localhost;dbname=lazy_test'
            user: root
            pass: 123123
          slave:
            dsn: 'mysql:dbname=lazy_test'
            query_options: { quote_column: true, quote_table: true }




12年4月22⽇日星期⽇日
database.yml
        data_sources:
          master:
            dsn: 'mysql:host=localhost;dbname=lazy_test'
            user: root
            pass: 123123
          slave:
            dsn: 'mysql:dbname=lazy_test'
            query_options: { quote_column: true, quote_table: true }




        schema
         // data source for writing
         $this->writeTo('master');

         // data source for reading
         $this->readFrom('slave');




12年4月22⽇日星期⽇日
拼裝時刻



12年4月22⽇日星期⽇日
LazyBone
                http://github.com/c9s/LazyBone.git




12年4月22⽇日星期⽇日
LazyBone =



12年4月22⽇日星期⽇日
LazyRecord
                + Roller Router
                + RESTful Plugin
                 + Backbone.js

12年4月22⽇日星期⽇日
Install LazyRecord



12年4月22⽇日星期⽇日
sudo bash -c "$(curl -s -L https://raw.github.com/c9s/LazyRecord/master/install.sh)"




12年4月22⽇日星期⽇日
Define config file



12年4月22⽇日星期⽇日
config/database.yml

                       ---
                       bootstrap:
                         - bootstrap.php
                       schema:
                         paths:
                           - model
                       data_sources:
                         default:
                           dsn: 'sqlite:/tmp/todos.db'




12年4月22⽇日星期⽇日
$ lazy build-conf config/database.yml


                             Convert YAML to PHP.
                             <?php
                             $config = require '.lazy.php';


                                          APC caches this automatically.


12年4月22⽇日星期⽇日
Define model



12年4月22⽇日星期⽇日
<?php

                class TodoSchema extends LazyRecordSchemaSchemaDeclare
                {
                    function schema()
                    {
                        $this->column('id')
                            ->primary()
                            ->autoIncrement()
                            ->integer();

                        $this->column('title')
                            ->text();

                        $this->column('done')
                            ->boolean()
                            ->default(false);

                        $this->column('created_on')
                            ->defaultBuilder( function() { return date('c'); } )
                            ->timestamp();
                    }

                    function bootstrap($model)
                    {
                        $model->create(array(
                            'title' => 'Foo',
                        ));
                    }
                }




12年4月22⽇日星期⽇日
Create static schema
                        files


12年4月22⽇日星期⽇日
12年4月22⽇日星期⽇日
$ lazy build-schema model/TodoSchema.php




12年4月22⽇日星期⽇日
$ lazy build-schema model/TodoSchema.php
 ...
 Classmap:
 ! TodoSchemaProxy                   => model/TodoSchemaProxy.php
 ! TodoBase                          => model/TodoBase.php
 ! Todo                              => model/Todo.php
 ! TodoCollectionBase                => model/TodoCollectionBase.php
 ! TodoCollection                    => model/TodoCollection.php
 Done




12年4月22⽇日星期⽇日
Initialize database



12年4月22⽇日星期⽇日
12年4月22⽇日星期⽇日
$ lazy build-sql model/TodoSchema.php




12年4月22⽇日星期⽇日
$ lazy build-sql model/TodoSchema.php
 Building SQL for TodoSchema
 --- SQL for TodoSchema
 CREATE TABLE todos (
 id integer primary key autoincrement,
 title text,
 done boolean default 0,
 created_on timestamp
 );




12年4月22⽇日星期⽇日
Integrate with your
                    application


12年4月22⽇日星期⽇日
<?php
         use LazyRecordConfigLoader;
         $config = new ConfigLoader;
         $config->load( __DIR__ . '/.lazy.php');
         $config->init();




12年4月22⽇日星期⽇日
Define routes



12年4月22⽇日星期⽇日
Roller Router
                High performance router for PHP




12年4月22⽇日星期⽇日
Roller Router
                •   APC cache

                •   FileSystem cache

                •   Use Array to store routes

                •   through PHP extension, can dispatch 1607% faster than
                    pure php version

                •   Annotation reader support

                •   RESTful plugin


12年4月22⽇日星期⽇日
$router = new RollerRouter;

         $router->get( '/blog/:id/:title'   , function($id,$title) {
             return 'Blog';
         });

         $router->post( '/blog/:year/:month/:id/:title',
                  array('Controller','method') );

         $router->any( '/path/to/:year' , array('Callback','method') , array(
             'year' => 'd+',
         ));




12年4月22⽇日星期⽇日
RouteSet


                     <?php
                     $subroutes = new RollerRouteSet;
                     $subroutes->add( '/subitem' , $cb );

                     $routes = new RollerRouteSet;
                     $routes->mount( '/item' , $subroutes );




                                           /item/subitem => $cb



12年4月22⽇日星期⽇日
Dispatch


                $r = $router->dispatch( isset($_SERVER['PATH_INFO'])
                            ? $_SERVER['PATH_INFO']
                            : '/' );

                if( $r ) {
                    echo $r();
                } else {
                    die('Page not found');
                }




12年4月22⽇日星期⽇日
RESTful Plugin



12年4月22⽇日星期⽇日
<?php
         $router = new RollerRouter( null, array(
             'cache_id' => 'router_demo'
         ));

         $restful = new RollerPluginRESTful(array(
                  'prefix' => '/=/restful' ));

         $restful->setGenericHandler( 'MyGenericHandler' );
         $router->addPlugin($restful);




12年4月22⽇日星期⽇日
Auto-generated routes



                  GET      /=/restful/posts
                  GET      /=/restful/posts.json
                  GET      /=/restful/posts.yml
                  GET      /=/restful/posts/23
                  GET      /=/restful/posts/23.json
                  POST     /=/restful/posts/23
                  DELETE   /=/restful/posts/23




12年4月22⽇日星期⽇日
Define Your Resource
                      Handler


12年4月22⽇日星期⽇日
<?php
                use RollerPluginRESTfulResourceHandler;
                use RollerPluginRESTfulGenericHandler;

                class MyGenericHandler extends GenericHandler
                {
                    public function create($resource) {
                    }

                    public function load($resource,$id) {
                    }

                    public function update($resource,$id) {
                    }

                    public function delete($resource,$id) {
                    }

                    public function find($resource) {
                    }
                }




12年4月22⽇日星期⽇日
<?php
                namespace LazyBoneResource;
                use RollerPluginRESTfulResourceHandler;
                use Todo;
                use TodoCollection;

                class TodoResource extends ResourceHandler
                {
                    public function create()
                    {
                        $vars = json_decode($this->readInput(),true);
                        $todo = new Todo;
                        $ret = $todo->create($vars);
                        if( $ret->success ) {
                            return $todo->toArray();
                        }
                        $this->codeBadRequest();
                        return array( 'error' => $ret->message );
                    }

                    public function update($id)
                    {
                        $todo = new Todo( $id );
                        if( ! $todo->id ) {
                            return $this->codeNotFound();
                        }

                        $vars = json_decode($this->readInput(),true);
                        unset( $vars['created_on'] ); // lazy record bug

                        if($vars) {
                            $todo->update( $vars );
                            return $todo->toArray();
                        }
                        return $this->codeBadRequest();
                    }

                    ....

12年4月22⽇日星期⽇日
Backbone.js



12年4月22⽇日星期⽇日
Todo = Backbone.Model.extend({
                    // Default attributes for the todo item.
                    defaults: function() {
                       return {
                          title: "empty todo...",
                          done: false
                          // order: Todos.nextOrder(),
                       };
                    },

                       // Toggle the `done` state of this todo item.
                      toggle: function() {
                          this.save({done: !this.get("done")});
                      },

                      clear: function() {
                          this.destroy();
                      }
                });




12年4月22⽇日星期⽇日
TodoList = Backbone.Collection.extend({
                    // Reference to this collection's model.
                    model: Todo,
                    url:"/=/todos",
                    done: function() {
                        return this.filter(function(todo){
                             return todo.get('done'); });
                    },
                    remaining: function() {
                        return this.without.apply(this, this.done());
                    },
              });




12年4月22⽇日星期⽇日
12年4月22⽇日星期⽇日
Hacking
                          forks welcome!

                http://github.com/c9s/LazyRecord.git




12年4月22⽇日星期⽇日
Q &A ?



12年4月22⽇日星期⽇日

More Related Content

What's hot

jQuery源码学习
jQuery源码学习jQuery源码学习
jQuery源码学习fangdeng
 
Bash shell script 教學
Bash shell script 教學Bash shell script 教學
Bash shell script 教學Ming-Sian Lin
 
Node.js开发体验
Node.js开发体验Node.js开发体验
Node.js开发体验QLeelulu
 
PHPUnit + Xdebug 单元测试技术
PHPUnit + Xdebug 单元测试技术PHPUnit + Xdebug 单元测试技术
PHPUnit + Xdebug 单元测试技术hoopchina
 
2009 CSBB LAB 新生訓練
2009 CSBB LAB 新生訓練2009 CSBB LAB 新生訓練
2009 CSBB LAB 新生訓練Abner Huang
 
OpenEJB - 另一個選擇
OpenEJB - 另一個選擇OpenEJB - 另一個選擇
OpenEJB - 另一個選擇Justin Lin
 
Javascript Training
Javascript TrainingJavascript Training
Javascript Trainingbeijing.josh
 
Python速成指南
Python速成指南Python速成指南
Python速成指南March Liu
 
Wind.js无障碍调试与排错
Wind.js无障碍调试与排错Wind.js无障碍调试与排错
Wind.js无障碍调试与排错jeffz
 
Free Marker中文文档
Free Marker中文文档Free Marker中文文档
Free Marker中文文档yiditushe
 
OpenWebSchool - 02 - PHP Part I
OpenWebSchool - 02 - PHP Part IOpenWebSchool - 02 - PHP Part I
OpenWebSchool - 02 - PHP Part IHung-yu Lin
 
Java华为面试题
Java华为面试题Java华为面试题
Java华为面试题yiditushe
 
Python xmlrpc-odoo
Python xmlrpc-odooPython xmlrpc-odoo
Python xmlrpc-odoorobin yang
 
iPhone,ios,Object-C基础入门
iPhone,ios,Object-C基础入门iPhone,ios,Object-C基础入门
iPhone,ios,Object-C基础入门Lucien Li
 
Patterns in Zend Framework
Patterns in Zend FrameworkPatterns in Zend Framework
Patterns in Zend FrameworkJace Ju
 
PHPUnit 入門介紹
PHPUnit 入門介紹PHPUnit 入門介紹
PHPUnit 入門介紹Jace Ju
 
.Net 技術研討(linq與架構開發)
.Net 技術研討(linq與架構開發).Net 技術研討(linq與架構開發)
.Net 技術研討(linq與架構開發)Gelis Wu
 
Mongodb
MongodbMongodb
Mongodbbj
 

What's hot (20)

jQuery源码学习
jQuery源码学习jQuery源码学习
jQuery源码学习
 
Bash shell script 教學
Bash shell script 教學Bash shell script 教學
Bash shell script 教學
 
Node.js开发体验
Node.js开发体验Node.js开发体验
Node.js开发体验
 
PHPUnit + Xdebug 单元测试技术
PHPUnit + Xdebug 单元测试技术PHPUnit + Xdebug 单元测试技术
PHPUnit + Xdebug 单元测试技术
 
2009 CSBB LAB 新生訓練
2009 CSBB LAB 新生訓練2009 CSBB LAB 新生訓練
2009 CSBB LAB 新生訓練
 
Ooredis
OoredisOoredis
Ooredis
 
OpenEJB - 另一個選擇
OpenEJB - 另一個選擇OpenEJB - 另一個選擇
OpenEJB - 另一個選擇
 
Javascript Training
Javascript TrainingJavascript Training
Javascript Training
 
Python速成指南
Python速成指南Python速成指南
Python速成指南
 
Wind.js无障碍调试与排错
Wind.js无障碍调试与排错Wind.js无障碍调试与排错
Wind.js无障碍调试与排错
 
Free Marker中文文档
Free Marker中文文档Free Marker中文文档
Free Marker中文文档
 
OpenWebSchool - 02 - PHP Part I
OpenWebSchool - 02 - PHP Part IOpenWebSchool - 02 - PHP Part I
OpenWebSchool - 02 - PHP Part I
 
Java华为面试题
Java华为面试题Java华为面试题
Java华为面试题
 
Python xmlrpc-odoo
Python xmlrpc-odooPython xmlrpc-odoo
Python xmlrpc-odoo
 
iPhone,ios,Object-C基础入门
iPhone,ios,Object-C基础入门iPhone,ios,Object-C基础入门
iPhone,ios,Object-C基础入门
 
Patterns in Zend Framework
Patterns in Zend FrameworkPatterns in Zend Framework
Patterns in Zend Framework
 
ios分享
ios分享ios分享
ios分享
 
PHPUnit 入門介紹
PHPUnit 入門介紹PHPUnit 入門介紹
PHPUnit 入門介紹
 
.Net 技術研討(linq與架構開發)
.Net 技術研討(linq與架構開發).Net 技術研討(linq與架構開發)
.Net 技術研討(linq與架構開發)
 
Mongodb
MongodbMongodb
Mongodb
 

Viewers also liked

Object Relational Mapping in PHP
Object Relational Mapping in PHPObject Relational Mapping in PHP
Object Relational Mapping in PHPRob Knight
 
Intro to Laravel PHP Framework
Intro to Laravel PHP FrameworkIntro to Laravel PHP Framework
Intro to Laravel PHP FrameworkBill Condo
 
Laravel Beginners Tutorial 1
Laravel Beginners Tutorial 1Laravel Beginners Tutorial 1
Laravel Beginners Tutorial 1Vikas Chauhan
 
JSON: The Basics
JSON: The BasicsJSON: The Basics
JSON: The BasicsJeff Fox
 
Android Application Development
Android Application DevelopmentAndroid Application Development
Android Application DevelopmentBenny Skogberg
 
Software Design Patterns in Laravel by Phill Sparks
Software Design Patterns in Laravel by Phill SparksSoftware Design Patterns in Laravel by Phill Sparks
Software Design Patterns in Laravel by Phill SparksPhill Sparks
 

Viewers also liked (12)

Laravel 5
Laravel 5Laravel 5
Laravel 5
 
Laravel Tutorial PPT
Laravel Tutorial PPTLaravel Tutorial PPT
Laravel Tutorial PPT
 
Object Relational Mapping in PHP
Object Relational Mapping in PHPObject Relational Mapping in PHP
Object Relational Mapping in PHP
 
Laravel Introduction
Laravel IntroductionLaravel Introduction
Laravel Introduction
 
Intro to Laravel PHP Framework
Intro to Laravel PHP FrameworkIntro to Laravel PHP Framework
Intro to Laravel PHP Framework
 
Laravel Beginners Tutorial 1
Laravel Beginners Tutorial 1Laravel Beginners Tutorial 1
Laravel Beginners Tutorial 1
 
JSON: The Basics
JSON: The BasicsJSON: The Basics
JSON: The Basics
 
Android ppt
Android pptAndroid ppt
Android ppt
 
Android Application Development
Android Application DevelopmentAndroid Application Development
Android Application Development
 
Radar Application
Radar ApplicationRadar Application
Radar Application
 
Software Design Patterns in Laravel by Phill Sparks
Software Design Patterns in Laravel by Phill SparksSoftware Design Patterns in Laravel by Phill Sparks
Software Design Patterns in Laravel by Phill Sparks
 
Android ppt
Android pptAndroid ppt
Android ppt
 

Similar to LazyRecord: The Fast ORM for PHP

基于Spring batch的大数据量并行处理
基于Spring batch的大数据量并行处理基于Spring batch的大数据量并行处理
基于Spring batch的大数据量并行处理Jacky Chi
 
Hadoop 安装
Hadoop 安装Hadoop 安装
Hadoop 安装feng lee
 
Discuz技术交流
Discuz技术交流Discuz技术交流
Discuz技术交流pigso
 
Migrations 與 Schema 操作
Migrations 與 Schema 操作Migrations 與 Schema 操作
Migrations 與 Schema 操作Shengyou Fan
 
Migrations 與 Schema操作
Migrations 與 Schema操作Migrations 與 Schema操作
Migrations 與 Schema操作Shengyou Fan
 
Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務
Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務
Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務Mu-Fan Teng
 
配置Oracle 10g 双向流复制
配置Oracle 10g 双向流复制配置Oracle 10g 双向流复制
配置Oracle 10g 双向流复制maclean liu
 
Flex 4.5 action data communication
Flex 4.5 action data communicationFlex 4.5 action data communication
Flex 4.5 action data communicationjexchan
 
用JAX-RS和Jersey完成RESTful Web Services
用JAX-RS和Jersey完成RESTful Web Services用JAX-RS和Jersey完成RESTful Web Services
用JAX-RS和Jersey完成RESTful Web Servicesjavatwo2011
 
Mastering Mustache
Mastering MustacheMastering Mustache
Mastering Mustachetinyhill
 
面向未来的重构
面向未来的重构面向未来的重构
面向未来的重构Kejun Zhang
 
線上埋碼資料收集實作
線上埋碼資料收集實作線上埋碼資料收集實作
線上埋碼資料收集實作FEG
 
旺铺前端设计和实现
旺铺前端设计和实现旺铺前端设计和实现
旺铺前端设计和实现hua qiu
 
Puppet安装测试
Puppet安装测试Puppet安装测试
Puppet安装测试Yiwei Ma
 
8, lamp
8, lamp8, lamp
8, lampted-xu
 
jQuery底层架构
jQuery底层架构jQuery底层架构
jQuery底层架构fangdeng
 
Drupal 版型設計 - 瞭解版型程式
Drupal 版型設計 - 瞭解版型程式Drupal 版型設計 - 瞭解版型程式
Drupal 版型設計 - 瞭解版型程式Chris Wu
 
Perl在nginx里的应用
Perl在nginx里的应用Perl在nginx里的应用
Perl在nginx里的应用琛琳 饶
 

Similar to LazyRecord: The Fast ORM for PHP (20)

基于Spring batch的大数据量并行处理
基于Spring batch的大数据量并行处理基于Spring batch的大数据量并行处理
基于Spring batch的大数据量并行处理
 
Hadoop 安装
Hadoop 安装Hadoop 安装
Hadoop 安装
 
Discuz技术交流
Discuz技术交流Discuz技术交流
Discuz技术交流
 
Migrations 與 Schema 操作
Migrations 與 Schema 操作Migrations 與 Schema 操作
Migrations 與 Schema 操作
 
Migrations 與 Schema操作
Migrations 與 Schema操作Migrations 與 Schema操作
Migrations 與 Schema操作
 
Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務
Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務
Mopcon2014 - 使用 Sinatra 結合 Ruby on Rails 輕鬆打造完整 Full Stack 網站加 API Service服務
 
配置Oracle 10g 双向流复制
配置Oracle 10g 双向流复制配置Oracle 10g 双向流复制
配置Oracle 10g 双向流复制
 
Flex 4.5 action data communication
Flex 4.5 action data communicationFlex 4.5 action data communication
Flex 4.5 action data communication
 
用JAX-RS和Jersey完成RESTful Web Services
用JAX-RS和Jersey完成RESTful Web Services用JAX-RS和Jersey完成RESTful Web Services
用JAX-RS和Jersey完成RESTful Web Services
 
Mastering Mustache
Mastering MustacheMastering Mustache
Mastering Mustache
 
Node way
Node wayNode way
Node way
 
面向未来的重构
面向未来的重构面向未来的重构
面向未来的重构
 
線上埋碼資料收集實作
線上埋碼資料收集實作線上埋碼資料收集實作
線上埋碼資料收集實作
 
旺铺前端设计和实现
旺铺前端设计和实现旺铺前端设计和实现
旺铺前端设计和实现
 
CRUD 綜合運用
CRUD 綜合運用CRUD 綜合運用
CRUD 綜合運用
 
Puppet安装测试
Puppet安装测试Puppet安装测试
Puppet安装测试
 
8, lamp
8, lamp8, lamp
8, lamp
 
jQuery底层架构
jQuery底层架构jQuery底层架构
jQuery底层架构
 
Drupal 版型設計 - 瞭解版型程式
Drupal 版型設計 - 瞭解版型程式Drupal 版型設計 - 瞭解版型程式
Drupal 版型設計 - 瞭解版型程式
 
Perl在nginx里的应用
Perl在nginx里的应用Perl在nginx里的应用
Perl在nginx里的应用
 

More from Lin Yo-An

Code Generation in PHP - PHPConf 2015
Code Generation in PHP - PHPConf 2015Code Generation in PHP - PHPConf 2015
Code Generation in PHP - PHPConf 2015Lin Yo-An
 
Getting merged
Getting mergedGetting merged
Getting mergedLin Yo-An
 
OSDC.TW - Gutscript for PHP haters
OSDC.TW - Gutscript for PHP hatersOSDC.TW - Gutscript for PHP haters
OSDC.TW - Gutscript for PHP hatersLin Yo-An
 
OSDC.TW 2014 building popular open source projects
OSDC.TW 2014   building popular open source projectsOSDC.TW 2014   building popular open source projects
OSDC.TW 2014 building popular open source projectsLin Yo-An
 
Happy Go Programming
Happy Go ProgrammingHappy Go Programming
Happy Go ProgrammingLin Yo-An
 
Happy Go Programming Part 1
Happy Go Programming Part 1Happy Go Programming Part 1
Happy Go Programming Part 1Lin Yo-An
 
Secret sauce of building php applications
Secret sauce of building php applicationsSecret sauce of building php applications
Secret sauce of building php applicationsLin Yo-An
 
Vim Script Programming
Vim Script ProgrammingVim Script Programming
Vim Script ProgrammingLin Yo-An
 
CPAN 模組二三事
CPAN 模組二三事CPAN 模組二三事
CPAN 模組二三事Lin Yo-An
 
Vim Hacks (OSSF)
Vim Hacks (OSSF)Vim Hacks (OSSF)
Vim Hacks (OSSF)Lin Yo-An
 
Perl.Hacks.On.Vim Perlchina
Perl.Hacks.On.Vim PerlchinaPerl.Hacks.On.Vim Perlchina
Perl.Hacks.On.Vim PerlchinaLin Yo-An
 
Perl.Hacks.On.Vim
Perl.Hacks.On.VimPerl.Hacks.On.Vim
Perl.Hacks.On.VimLin Yo-An
 

More from Lin Yo-An (13)

Code Generation in PHP - PHPConf 2015
Code Generation in PHP - PHPConf 2015Code Generation in PHP - PHPConf 2015
Code Generation in PHP - PHPConf 2015
 
Getting merged
Getting mergedGetting merged
Getting merged
 
OSDC.TW - Gutscript for PHP haters
OSDC.TW - Gutscript for PHP hatersOSDC.TW - Gutscript for PHP haters
OSDC.TW - Gutscript for PHP haters
 
OSDC.TW 2014 building popular open source projects
OSDC.TW 2014   building popular open source projectsOSDC.TW 2014   building popular open source projects
OSDC.TW 2014 building popular open source projects
 
Happy Go Programming
Happy Go ProgrammingHappy Go Programming
Happy Go Programming
 
Happy Go Programming Part 1
Happy Go Programming Part 1Happy Go Programming Part 1
Happy Go Programming Part 1
 
Secret sauce of building php applications
Secret sauce of building php applicationsSecret sauce of building php applications
Secret sauce of building php applications
 
Vim Script Programming
Vim Script ProgrammingVim Script Programming
Vim Script Programming
 
CPAN 模組二三事
CPAN 模組二三事CPAN 模組二三事
CPAN 模組二三事
 
Vim Hacks (OSSF)
Vim Hacks (OSSF)Vim Hacks (OSSF)
Vim Hacks (OSSF)
 
Perl.Hacks.On.Vim Perlchina
Perl.Hacks.On.Vim PerlchinaPerl.Hacks.On.Vim Perlchina
Perl.Hacks.On.Vim Perlchina
 
Perl.Hacks.On.Vim
Perl.Hacks.On.VimPerl.Hacks.On.Vim
Perl.Hacks.On.Vim
 
Vim Hacks
Vim HacksVim Hacks
Vim Hacks
 

LazyRecord: The Fast ORM for PHP

  • 1. LazyRecord The Fast PHP ORM 林佑安 Yo-An Lin (c9s) 12年4月22⽇日星期⽇日
  • 2. .metadata • 林佑安 (c9s) • 190 repo/projects on GitHub • Perl programming since 2008 • PHP programming since last year • c, c++, javascript, obj-c, ruby, python, haskell, java, c#,VB .NET ... 12年4月22⽇日星期⽇日
  • 3. Why another PHP ORM ? 12年4月22⽇日星期⽇日
  • 4. PHP ORMs • Doctrine 12年4月22⽇日星期⽇日
  • 5. PHP ORMs • Doctrine • Propel 12年4月22⽇日星期⽇日
  • 6. PHP ORMs • Doctrine • Propel • Idiorm / Paris 12年4月22⽇日星期⽇日
  • 7. Propel / Doctrine • Propel uses XML Schema file. 12年4月22⽇日星期⽇日
  • 8. Propel / Doctrine • Propel uses XML Schema file. • Doctrine uses XML/YAML/Annotations. 12年4月22⽇日星期⽇日
  • 9. Propel / Doctrine • Propel uses XML Schema file. • Doctrine uses XML/YAML/Annotations. • Slow & Fat. 12年4月22⽇日星期⽇日
  • 10. Propel / Doctrine • Propel uses XML Schema file. • Doctrine uses XML/YAML/Annotations. • Slow & Fat. • Doctrine is too complicated. 12年4月22⽇日星期⽇日
  • 12. • XML for configuration file. • XML for schema file. • XML for everything. • Concepts are from Java, too complicated. 12年4月22⽇日星期⽇日
  • 13. Propel XML runtime.conf 12年4月22⽇日星期⽇日
  • 14. <?xml version="1.0"?> <config> <log> <ident>propel-bookstore</ident> <type>console</type> <level>7</level> </log> <propel> <datasources default="bookstore"> <datasource id="bookstore"> <adapter>sqlite</adapter> <connection> <classname>DebugPDO</classname> <dsn>mysql:host=localhost;dbname=bookstore</dsn> <user>testuser</user> <password>password</password> <options> <option id="ATTR_PERSISTENT">false</option> </options> <attributes> <option id="ATTR_EMULATE_PREPARES">true</option> </attributes> <settings> <setting id="charset">utf8</setting> <setting id="queries"> <query>set search_path myschema, public</query><!-- automatically set postgresql's search_path --> <query>INSERT INTO BAR ('hey', 'there')</query><!-- execute some other query --> </setting> </settings> </connection> <slaves> <connection> <dsn>mysql:host=slave-server1; dbname=bookstore</dsn> </connection> <connection> <dsn>mysql:host=slave-server2; dbname=bookstore</dsn> </connection> </slaves> </datasource> </datasources> <debugpdo> <logging> <details> <method> <enabled>true</enabled> </method> <time> <enabled>true</enabled> <precision>3</precision> </time> <mem> <enabled>true</enabled> <precision>1</precision> 12年4月22⽇日星期⽇日 </mem>
  • 15. <datasource id="bookstore"> <adapter>sqlite</adapter> <connection> <classname>DebugPDO</classname> <dsn>mysql:host=localhost;dbname=bookstore</dsn> <user>testuser</user> <password>password</password> <options> <option id="ATTR_PERSISTENT">false</option> </options> <attributes> <option id="ATTR_EMULATE_PREPARES">true</option> </attributes> <settings> <setting id="charset">utf8</setting> <setting id="queries"> <query>set search_path myschema, public</query><!-- automatically set postgresql's search_path --> <query>INSERT INTO BAR ('hey', 'there')</query><!-- execute some other query --> </setting> </settings> </connection> <slaves> <connection> <dsn>mysql:host=slave-server1; dbname=bookstore</dsn> </connection> <connection> <dsn>mysql:host=slave-server2; dbname=bookstore</dsn> </connection> </slaves> </datasource> </datasources> <debugpdo> <logging> <details> <method> <enabled>true</enabled> </method> <time> <enabled>true</enabled> <precision>3</precision> </time> <mem> <enabled>true</enabled> <precision>1</precision> </mem> </details> </logging> </debugpdo> </propel> </config> 12年4月22⽇日星期⽇日
  • 17. It should be simpler 12年4月22⽇日星期⽇日
  • 18. Inspirations • JiftyDBI / Perl • KiokuDB / Perl • ActiveRecord / Ruby • Propel / PHP 12年4月22⽇日星期⽇日
  • 20. client = Client.find(10) client = Client.first Client.where("orders_count = ?", params[:orders]) Client.where("created_at >= :start_date AND created_at <= :end_date", {:start_date => params[:start_date], :end_date => params[:end_date]}) Client.order("created_at DESC") Client.limit(5).offset(30) 12年4月22⽇日星期⽇日
  • 21. Object::Declare use Object::Declare ['MyApp::Column', 'MyApp::Param']; my %objects = declare { param foo => !is global, is immutable, valid_values are qw( more values ); column bar => field1 is 'value', field2 is 'some_other_value', sub_params are param( is happy ), param ( is sad ); }; print $objects{foo}; # a MyApp::Param object print $objects{bar}; # a MyApp::Column object # Assuming that MyApp::Column::new simply blesses into a hash... print $objects{bar}{sub_params}[0]; # a MyApp::Param object print $objects{bar}{sub_params}[1]; # a MyApp::Param object Audrey Tang 唐鳳 2006 12年4月22⽇日星期⽇日
  • 22. Jifty::DBI package Simple; use Jifty::DBI::Schema; use Jifty::DBI::Record schema { column foo => type is 'text'; column bar => type is 'text'; }; 12年4月22⽇日星期⽇日
  • 23. Jifty::DBI package TestApp::Model::Phone; use Jifty::DBI::Schema; use Jifty::DBI::Record schema { column user => references TestApp::Model::User by 'id', is mandatory; column type => ...; column value => validator is sub { ... }, default is sub { } ; }; 12年4月22⽇日星期⽇日
  • 24. Jifty Model Schema 12年4月22⽇日星期⽇日
  • 25. Jifty Model Schema ⇛ Action 12年4月22⽇日星期⽇日
  • 26. Jifty Model Schema ⇛ Action ⇛ CRUD 12年4月22⽇日星期⽇日
  • 27. Jifty App::Model::Phone ☚ write once 12年4月22⽇日星期⽇日
  • 28. Jifty App::Model::Phone App::Model::PhoneCollection 12年4月22⽇日星期⽇日
  • 29. Jifty App::Model::Phone App::Model::PhoneCollection App::Action::CreatePhone 12年4月22⽇日星期⽇日
  • 30. Jifty App::Model::Phone App::Model::PhoneCollection App::Action::CreatePhone App::Action::UpdatePhone 12年4月22⽇日星期⽇日
  • 31. Jifty App::Model::Phone App::Model::PhoneCollection App::Action::CreatePhone App::Action::UpdatePhone App::Action::DeletePhone 12年4月22⽇日星期⽇日
  • 32. Jifty App::Model::Phone App::Model::PhoneCollection App::Action::CreatePhone App::Action::UpdatePhone App::Action::DeletePhone $phone->as_create_action()->render(); 12年4月22⽇日星期⽇日
  • 34. What we need • Can use PHP closures for validation, default value, completion ..etc. • Everything should be lazy. • Simple API • No overdesign. • Mixin schema • CRUD generation. • Front-end CRUD integration. 12年4月22⽇日星期⽇日
  • 35. PHP 5.3 Characteristic • APC is fast. • json_encode / json_decode (file) are slower than require a simple array from php source code. • function is faster than class method. • class method is slower than properties. • magic method is slower than normal class method. • array is faster than object. 12年4月22⽇日星期⽇日
  • 36. $array[] vs array_push https://github.com/c9s/SimpleBench 12年4月22⽇日星期⽇日
  • 37. Function calls https://github.com/c9s/SimpleBench 12年4月22⽇日星期⽇日
  • 39. EteDB • Initialize model schema in runtime. • Schema is defined in Model (in __constructor). • MySQL only. • dynamic class generator (using eval) • too slow. 12年4月22⽇日星期⽇日
  • 41. LazyRecord • Lazy schema loader • SQL Generator • Lazy attribute for MySQL, PgSQL, SQLite • Lazy class loader • Lazy connection • SplClassLoader • Static class • ... etc generator 12年4月22⽇日星期⽇日
  • 43. SQLBuilder • A Simple SQL Generator. • Prevent Injection. • Migration generator. (index, alter table...etc) • Support SQLite, Pgsql, Mysql syntax. • Pure SQL or with named-parameters. 12年4月22⽇日星期⽇日
  • 44. <?php $sqlbuilder = new SQLBuilderQueryBuilder( $driver ); $sql = $sqlbuilder->table('authors')->insert([ 'name' => 'Mary', 'address' => 'Paris', ])->build(); 12年4月22⽇日星期⽇日
  • 45. -- General syntax INSERT INTO authors ( name , address ) VALUES ( 'Name' , 'Address' ); -- PgSQL INSERT INTO "Authors" ( "Name" , "Address" ) VALUES ( 'Name' , 'Address' ); -- MySQL INSERT INTO `Authors` ( `Name` , `Address` ) VALUES ( 'Name' , 'Address' ); -- PDO INSERT INTO authors ( name , address ) VALUES ( ? , ? ); INSERT INTO authors ( name , address ) VALUES ( :name , :address ); 12年4月22⽇日星期⽇日
  • 46. <?php $sql = $builder->table('Member')->select('*') ->where() ->equal( 'a' , 'bar' ) // a = 'bar' ->notEqual( 'a' , 'bar' ) // a != 'bar' ->is( 'a' , 'null' ) // a is null ->isNot( 'a' , 'null' ) // a is not equal ->greater( 'a' , '2011-01-01' ); ->greater( 'a' , ['date(2011-01-01)'] ); // do not escape ->or()->less( 'a' , 123 ) ->and()->like( 'content' , '%content%' ); ->group() // and ( a = 123 or b != 123 ) ->is( 'a' , 123 ) ->isNot( 'b', 123 ) ->ungroup() ->build(); 12年4月22⽇日星期⽇日
  • 49. <?php $author = new Author; $ret = $author->create([ 'name' => "Deflator Test $i", 'country' => 'Tokyo', 'confirmed' => true, 'date' => new DateTime('2011-01-01 00:00:00'), ]); if( $ret->success ) { echo "Created!"; } 12年4月22⽇日星期⽇日
  • 50. <?php $ret = $author->update(array( 'name' => 'Bar' )); if( $ret->success ) { echo "Updated!"; } else { echo $ret; // __toString support } 12年4月22⽇日星期⽇日
  • 51. <?php $record = Author::load(array( 'name' => 'Foo' )); // To find a record with primary key: $record = Author::load( 1 ); // To update a record (static): $ret = Author::update( array( 'name' => 'Author' ))->where() ->equal('id',3) ->execute(); 12年4月22⽇日星期⽇日
  • 52. $author->toJson(); $author->toArray(); $author->toXml(); $author->toYaml(); 12年4月22⽇日星期⽇日
  • 54. Iterator <?php $authors = new AuthorCollection; foreach( $authors as $author ) { echo $author->name , "n" } 12年4月22⽇日星期⽇日
  • 55. SQLBuilder Mix-In <?php $names = new NameCollection; $names->where() ->equal('name','Foo') ->groupBy('name','address'); ?> 12年4月22⽇日星期⽇日
  • 56. Filter <?php $newCollection = $names->filter(function($item) { // do something else })->filter(function($item) { return $item->confirmed; }); ?> 12年4月22⽇日星期⽇日
  • 57. Each <?php $names->each(function($item) { $item->update([ .... ]); }); ?> 12年4月22⽇日星期⽇日
  • 58. Collection Pager <?php /* page 1, 10 per page */ $authors = new AuthorCollection; $pager = $authors->pager(1,10); $pager = $authors->pager(); $items = $pager->items(); $pager->next(); // next page ?> Integrate with OFFSET & LIMIT 12年4月22⽇日星期⽇日
  • 59. Relationship <?php // has many $address = $author->addresses->create([ 'address' => 'farfaraway' ]); // create related address $author->addresses[] = [ 'address' => 'Harvard' ]; $addresses = $author->addresses->items(); foreach( $author->addresses as $address ) { echo $address->address , "n"; } 12年4月22⽇日星期⽇日
  • 61. Powered by CascadingAttribute.php 12年4月22⽇日星期⽇日
  • 62. <?php use LazyRecordSchemaSchemaDeclare; class AddressSchema extends SchemaDeclare { function schema() { } } 12年4月22⽇日星期⽇日
  • 63. <?php use LazyRecordSchemaSchemaDeclare; class AddressSchema extends SchemaDeclare { function schema() { $this->column('address') ->varchar(128); } } 12年4月22⽇日星期⽇日
  • 64. <?php use LazyRecordSchemaSchemaDeclare; class AddressSchema extends SchemaDeclare { function schema() { $this->column('address') ->integer(); } } 12年4月22⽇日星期⽇日
  • 65. <?php use LazyRecordSchemaSchemaDeclare; class AddressSchema extends SchemaDeclare { function schema() { $this->column('address') ->timestamp(); } } 12年4月22⽇日星期⽇日
  • 66. Default value & builder 12年4月22⽇日星期⽇日
  • 67. $this->column('name') ->varchar(30) ->default('Default'); 12年4月22⽇日星期⽇日
  • 68. $this->column('name') ->varchar(30) ->default( array('current_timestamp') ); 12年4月22⽇日星期⽇日
  • 69. $this->column('name') ->varchar(30) ->defaultBuilder(function() { return date('c'); }) 12年4月22⽇日星期⽇日
  • 70. $this->column('name') ->varchar(30) ->default('Default') ->default( array('current_timestamp') ) ->defaultBuilder(function() { return date('c'); }) 12年4月22⽇日星期⽇日
  • 72. $this->column('name') ->varchar(30) ->validator('ValidatorClass') 12年4月22⽇日星期⽇日
  • 73. $this->column('name') ->varchar(30) ->validator( array('ValidatorClass','method') ) 12年4月22⽇日星期⽇日
  • 74. $this->column('name') ->varchar(30) ->validator('function_name') 12年4月22⽇日星期⽇日
  • 75. $this->column('name') ->varchar(30) ->validator(function($val) { .... }) 12年4月22⽇日星期⽇日
  • 77. $this->column('name') ->varchar(30) ->filter( function($val) { return preg_replace('#word#','zz',$val); }); 12年4月22⽇日星期⽇日
  • 79. use LazyRecordSchemaSchemaDeclare; class NameSchema extends SchemaDeclare { function schema() { $this->column('created_on') ->date() ->isa('DateTime') ->deflator( function($val) { if( is_a( $val, 'DateTime' ) ) return $val->format('Y-m-d'); elseif( is_integer($val) ) { return strftime( '%Y-%m-%d' , $val ); } return $val; }) ->inflator( function($val) { return new DateTime( $val ); }); } } 12年4月22⽇日星期⽇日
  • 80. $name->created_on; // DateTime object $name->created_on->format('Y-m-d'); $name->create([ 'created_on' => new DateTime; ]); 12年4月22⽇日星期⽇日
  • 82. $this->mixin('MetadataMixinSchema'); $this->mixin('I18nMixinSchema'); $this->mixin('CommentMinxSchema'); 12年4月22⽇日星期⽇日
  • 84. database.yml data_sources: master: dsn: 'mysql:host=localhost;dbname=lazy_test' user: root pass: 123123 12年4月22⽇日星期⽇日
  • 85. database.yml data_sources: master: dsn: 'mysql:host=localhost;dbname=lazy_test' user: root pass: 123123 slave: dsn: 'mysql:dbname=lazy_test' query_options: { quote_column: true, quote_table: true } 12年4月22⽇日星期⽇日
  • 86. database.yml data_sources: master: dsn: 'mysql:host=localhost;dbname=lazy_test' user: root pass: 123123 slave: dsn: 'mysql:dbname=lazy_test' query_options: { quote_column: true, quote_table: true } schema // data source for writing $this->writeTo('master'); // data source for reading $this->readFrom('slave'); 12年4月22⽇日星期⽇日
  • 88. LazyBone http://github.com/c9s/LazyBone.git 12年4月22⽇日星期⽇日
  • 90. LazyRecord + Roller Router + RESTful Plugin + Backbone.js 12年4月22⽇日星期⽇日
  • 92. sudo bash -c "$(curl -s -L https://raw.github.com/c9s/LazyRecord/master/install.sh)" 12年4月22⽇日星期⽇日
  • 94. config/database.yml --- bootstrap: - bootstrap.php schema: paths: - model data_sources: default: dsn: 'sqlite:/tmp/todos.db' 12年4月22⽇日星期⽇日
  • 95. $ lazy build-conf config/database.yml Convert YAML to PHP. <?php $config = require '.lazy.php'; APC caches this automatically. 12年4月22⽇日星期⽇日
  • 97. <?php class TodoSchema extends LazyRecordSchemaSchemaDeclare { function schema() { $this->column('id') ->primary() ->autoIncrement() ->integer(); $this->column('title') ->text(); $this->column('done') ->boolean() ->default(false); $this->column('created_on') ->defaultBuilder( function() { return date('c'); } ) ->timestamp(); } function bootstrap($model) { $model->create(array( 'title' => 'Foo', )); } } 12年4月22⽇日星期⽇日
  • 98. Create static schema files 12年4月22⽇日星期⽇日
  • 100. $ lazy build-schema model/TodoSchema.php 12年4月22⽇日星期⽇日
  • 101. $ lazy build-schema model/TodoSchema.php ... Classmap: ! TodoSchemaProxy => model/TodoSchemaProxy.php ! TodoBase => model/TodoBase.php ! Todo => model/Todo.php ! TodoCollectionBase => model/TodoCollectionBase.php ! TodoCollection => model/TodoCollection.php Done 12年4月22⽇日星期⽇日
  • 104. $ lazy build-sql model/TodoSchema.php 12年4月22⽇日星期⽇日
  • 105. $ lazy build-sql model/TodoSchema.php Building SQL for TodoSchema --- SQL for TodoSchema CREATE TABLE todos ( id integer primary key autoincrement, title text, done boolean default 0, created_on timestamp ); 12年4月22⽇日星期⽇日
  • 106. Integrate with your application 12年4月22⽇日星期⽇日
  • 107. <?php use LazyRecordConfigLoader; $config = new ConfigLoader; $config->load( __DIR__ . '/.lazy.php'); $config->init(); 12年4月22⽇日星期⽇日
  • 109. Roller Router High performance router for PHP 12年4月22⽇日星期⽇日
  • 110. Roller Router • APC cache • FileSystem cache • Use Array to store routes • through PHP extension, can dispatch 1607% faster than pure php version • Annotation reader support • RESTful plugin 12年4月22⽇日星期⽇日
  • 111. $router = new RollerRouter; $router->get( '/blog/:id/:title' , function($id,$title) { return 'Blog'; }); $router->post( '/blog/:year/:month/:id/:title', array('Controller','method') ); $router->any( '/path/to/:year' , array('Callback','method') , array( 'year' => 'd+', )); 12年4月22⽇日星期⽇日
  • 112. RouteSet <?php $subroutes = new RollerRouteSet; $subroutes->add( '/subitem' , $cb ); $routes = new RollerRouteSet; $routes->mount( '/item' , $subroutes ); /item/subitem => $cb 12年4月22⽇日星期⽇日
  • 113. Dispatch $r = $router->dispatch( isset($_SERVER['PATH_INFO']) ? $_SERVER['PATH_INFO'] : '/' ); if( $r ) { echo $r(); } else { die('Page not found'); } 12年4月22⽇日星期⽇日
  • 115. <?php $router = new RollerRouter( null, array( 'cache_id' => 'router_demo' )); $restful = new RollerPluginRESTful(array( 'prefix' => '/=/restful' )); $restful->setGenericHandler( 'MyGenericHandler' ); $router->addPlugin($restful); 12年4月22⽇日星期⽇日
  • 116. Auto-generated routes GET /=/restful/posts GET /=/restful/posts.json GET /=/restful/posts.yml GET /=/restful/posts/23 GET /=/restful/posts/23.json POST /=/restful/posts/23 DELETE /=/restful/posts/23 12年4月22⽇日星期⽇日
  • 117. Define Your Resource Handler 12年4月22⽇日星期⽇日
  • 118. <?php use RollerPluginRESTfulResourceHandler; use RollerPluginRESTfulGenericHandler; class MyGenericHandler extends GenericHandler { public function create($resource) { } public function load($resource,$id) { } public function update($resource,$id) { } public function delete($resource,$id) { } public function find($resource) { } } 12年4月22⽇日星期⽇日
  • 119. <?php namespace LazyBoneResource; use RollerPluginRESTfulResourceHandler; use Todo; use TodoCollection; class TodoResource extends ResourceHandler { public function create() { $vars = json_decode($this->readInput(),true); $todo = new Todo; $ret = $todo->create($vars); if( $ret->success ) { return $todo->toArray(); } $this->codeBadRequest(); return array( 'error' => $ret->message ); } public function update($id) { $todo = new Todo( $id ); if( ! $todo->id ) { return $this->codeNotFound(); } $vars = json_decode($this->readInput(),true); unset( $vars['created_on'] ); // lazy record bug if($vars) { $todo->update( $vars ); return $todo->toArray(); } return $this->codeBadRequest(); } .... 12年4月22⽇日星期⽇日
  • 121. Todo = Backbone.Model.extend({ // Default attributes for the todo item. defaults: function() { return { title: "empty todo...", done: false // order: Todos.nextOrder(), }; }, // Toggle the `done` state of this todo item. toggle: function() { this.save({done: !this.get("done")}); }, clear: function() { this.destroy(); } }); 12年4月22⽇日星期⽇日
  • 122. TodoList = Backbone.Collection.extend({ // Reference to this collection's model. model: Todo, url:"/=/todos", done: function() { return this.filter(function(todo){ return todo.get('done'); }); }, remaining: function() { return this.without.apply(this, this.done()); }, }); 12年4月22⽇日星期⽇日
  • 124. Hacking forks welcome! http://github.com/c9s/LazyRecord.git 12年4月22⽇日星期⽇日