secret sauce of building php applications

Post on 13-May-2015

8.254 Views

Category:

Technology

6 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Secret sauce of building PHP applications

林佑安 (Yo-An Lin)aka c9s

Monday, January 14, 13

About

• GitHub, Twitter, Plurk: @c9s

• 220+ GitHub repository in Perl, VimL, PHP, JavaScript and Go.

Monday, January 14, 13

為什麼是 PHP?

Monday, January 14, 13

Hey! PHP Sucks

Monday, January 14, 13

PHP Sucks!

Monday, January 14, 13

2000 年開始使⽤用 PHP websites ⼤大幅成⻑⾧長

Monday, January 14, 13

Monday, January 14, 13

High traffic PHP websites

⾼高流量 PHP 網站

Monday, January 14, 13

Monday, January 14, 13

Monday, January 14, 13

Monday, January 14, 13

Monday, January 14, 13

Monday, January 14, 13

Monday, January 14, 13

Monday, January 14, 13

http://highscalability.com/flickr-architecture

Monday, January 14, 13

Monday, January 14, 13

Monday, January 14, 13

Monday, January 14, 13

Monday, January 14, 13

Monday, January 14, 13

Monday, January 14, 13

Monday, January 14, 13

Monday, January 14, 13

Monday, January 14, 13

⼤大家都跑 PHP

Monday, January 14, 13

為什麼?

Monday, January 14, 13

劣即是夯唐鳳 - OSDC 2012

Monday, January 14, 13

有多夯?

Monday, January 14, 13

去街上問

Monday, January 14, 13

⼗十個有九個都會寫 PHP

Monday, January 14, 13

你Grandma都會寫 PHP

我也寫 PHP

Monday, January 14, 13

但是Monday, January 14, 13

你還在使⽤用⽯石器時代的 PHP 嗎?

Monday, January 14, 13

⽯石器時代 PHP ?

Monday, January 14, 13

⽯石器時代義⼤大利麵

Monday, January 14, 13

⽯石器時代 PHP

Monday, January 14, 13

⽯石器時代 PHP

• Dreamweaver PHP 產⽣生器 (⻤⿁鬼才看得懂)

Monday, January 14, 13

⽯石器時代 PHP

• Dreamweaver PHP 產⽣生器 (⻤⿁鬼才看得懂)

• Copy & Paste (品質低落)

Monday, January 14, 13

⽯石器時代 PHP

• Dreamweaver PHP 產⽣生器 (⻤⿁鬼才看得懂)

• Copy & Paste (品質低落)

• .inc 附檔名 (安全漏洞)

Monday, January 14, 13

⽯石器時代 PHP

• Dreamweaver PHP 產⽣生器 (⻤⿁鬼才看得懂)

• Copy & Paste (品質低落)

• .inc 附檔名 (安全漏洞)

• ⼤大量的 require 呼叫循環 (效能問題)

Monday, January 14, 13

⽯石器時代 PHP

• Dreamweaver PHP 產⽣生器 (⻤⿁鬼才看得懂)

• Copy & Paste (品質低落)

• .inc 附檔名 (安全漏洞)

• ⼤大量的 require 呼叫循環 (效能問題)

• HTML Render 不做 Escape (XSS 漏洞)

Monday, January 14, 13

⽯石器時代 PHP

• Dreamweaver PHP 產⽣生器 (⻤⿁鬼才看得懂)

• Copy & Paste (品質低落)

• .inc 附檔名 (安全漏洞)

• ⼤大量的 require 呼叫循環 (效能問題)

• HTML Render 不做 Escape (XSS 漏洞)

• POST/GET 從不過濾 (SQL Injection)

Monday, January 14, 13

為什麼?

Monday, January 14, 13

24⼩小時學會 PHP

Monday, January 14, 13

• 語⾔言學習⼊入⾨門⾨門檻低

24⼩小時學會 PHP

Monday, January 14, 13

• 語⾔言學習⼊入⾨門⾨門檻低• 隨便寫,丟給 Apache 就可以執⾏行了

24⼩小時學會 PHP

Monday, January 14, 13

• 語⾔言學習⼊入⾨門⾨門檻低• 隨便寫,丟給 Apache 就可以執⾏行了

• $_POST, $_GET 是什麼⻤⿁鬼 (管他,可以跑就好了)

24⼩小時學會 PHP

Monday, January 14, 13

• 語⾔言學習⼊入⾨門⾨門檻低• 隨便寫,丟給 Apache 就可以執⾏行了

• $_POST, $_GET 是什麼⻤⿁鬼 (管他,可以跑就好了)

• 義⼤大利麵好煮⼜又好吃,維護是什麼?沒聽過!

24⼩小時學會 PHP

Monday, January 14, 13

寫這樣的 PHP您⼼心安嗎?

Monday, January 14, 13

The Modern PHP Solution現代 PHP 解決⽅方案

Monday, January 14, 13

Modern Tools

• PSR

• Composer / Onion / PEAR / Pyrus

• phpbrew / phpenv / phpbuild

• ClassLoader via spl_autoload_* functions

• New language features (traits, spl, generator...)

Monday, January 14, 13

PHP spl_autoload_*

Monday, January 14, 13

Zend Engine Compilation

Monday, January 14, 13

Request

ScanningLexing

AST ParsingCompilation

Execution

File a.php

Output

Zend EngineCompilation

Monday, January 14, 13

Request

ScanningLexingParsing

Compilation

Execution

File a.php

Output

Require b.php Require c.php Require d.php Require e.php

ScanningLexingParsing

Compilation

ScanningLexingParsing

Compilation

ScanningLexingParsing

Compilation

Monday, January 14, 13

Request

ScanningLexingParsing

Compilation

Execution

File a.php

Output

Require b.php Require c.php Require d.php Require e.php

ScanningLexingParsing

Compilation

ScanningLexingParsing

Compilation

ScanningLexingParsing

Compilation

只⽤用到 b.php 的 function

Monday, January 14, 13

Request

ScanningLexingParsing

Compilation

Execution

File a.php

Output

Require b.php Require c.php Require d.php Require e.php

ScanningLexingParsing

Compilation

ScanningLexingParsing

Compilation

ScanningLexingParsing

Compilation

資源浪費 (CPU + Memory) x 100,000

x 100,000

Monday, January 14, 13

那 APC 呢?

Monday, January 14, 13

Request

ScanningLexingParsing

Compilation

Execution

File a.php

Output

Require b.php Require c.php Require d.php Require e.php

fstat checkunserialize op cache

fstat checkunserialize op cache

fstat checkunserialize op cache

仍須作 filestat check (default)Memory 照樣浪費

x 100,000

Monday, January 14, 13

Monday, January 14, 13

這就是WordPress 慢的原因

http://talks.php.net/presentations/slides/intro/wp_inclued1.png

Monday, January 14, 13

PHP spl_autoload_*

• PHP 5.3+ 的新功能。

Monday, January 14, 13

PHP spl_autoload_*

• PHP 5.3+ 的新功能。

• 可註冊⾃自訂的類別載⼊入策略 (autoloading strategy)

Monday, January 14, 13

PHP spl_autoload_*

• PHP 5.3+ 的新功能。

• 可註冊⾃自訂的類別載⼊入策略 (autoloading strategy)

• 對於找不到定義的類別,⾃自動呼叫 class loader 進⾏行類別的⾃自動載⼊入。

Monday, January 14, 13

PHP spl_autoload_*

• PHP 5.3+ 的新功能。

• 可註冊⾃自訂的類別載⼊入策略 (autoloading strategy)

• 對於找不到定義的類別,⾃自動呼叫 class loader 進⾏行類別的⾃自動載⼊入。

• 每個 request 只會載⼊入⾃自⼰己需要的 class,⽤用越少,載越少。

Monday, January 14, 13

PSR⾞車同軌,書同⽂文

Monday, January 14, 13

PSR-0 for PHP class

定義了 ClassLoader 的規範

Monday, January 14, 13

$bar = new Foo\Bar;spl_autoload_call(“Foo\Bar”)

Monday, January 14, 13

Package dependency套件相依性

Monday, January 14, 13

套件相依性可以很混亂

Monday, January 14, 13

Package dependencies

Monday, January 14, 13

Package dependencies

Monday, January 14, 13

Package dependencies

Monday, January 14, 13

Composer

http://www.slideshare.net/naderman/composer-9206307

https://github.com/composer/composer

Monday, January 14, 13

Composer

• composer.json 取材於 Node.js NPM

http://www.slideshare.net/naderman/composer-9206307

https://github.com/composer/composer

Monday, January 14, 13

Composer

• composer.json 取材於 Node.js NPM

• 更好的相依性解決⽅方案 SAT,取材於 OpenSuse 的 minisat / libzypper

http://www.slideshare.net/naderman/composer-9206307

https://github.com/composer/composer

Monday, January 14, 13

Composer

• composer.json 取材於 Node.js NPM

• 更好的相依性解決⽅方案 SAT,取材於 OpenSuse 的 minisat / libzypper

• Satis package repository 可架設套件庫

http://www.slideshare.net/naderman/composer-9206307

https://github.com/composer/composer

Monday, January 14, 13

Composer

• composer.json 取材於 Node.js NPM

• 更好的相依性解決⽅方案 SAT,取材於 OpenSuse 的 minisat / libzypper

• Satis package repository 可架設套件庫

• composer.lock 可鎖定套件相依資料

http://www.slideshare.net/naderman/composer-9206307

https://github.com/composer/composer

Monday, January 14, 13

Composer

• composer.json 取材於 Node.js NPM

• 更好的相依性解決⽅方案 SAT,取材於 OpenSuse 的 minisat / libzypper

• Satis package repository 可架設套件庫

• composer.lock 可鎖定套件相依資料

• ⼯工具逐漸成熟,越來越多⼈人使⽤用http://www.slideshare.net/naderman/composer-9206307

https://github.com/composer/composer

Monday, January 14, 13

Onionhttp://github.com/c9s/Onion

Monday, January 14, 13

Onion

• PEAR 向後相容⼯工具

http://github.com/c9s/Onion

Monday, January 14, 13

Onion

• PEAR 向後相容⼯工具

• 提供簡易的套件定義 package.ini

http://github.com/c9s/Onion

Monday, January 14, 13

Onion

• PEAR 向後相容⼯工具

• 提供簡易的套件定義 package.ini

• 可快速打包成 PEAR 套件

http://github.com/c9s/Onion

Monday, January 14, 13

Onion

• PEAR 向後相容⼯工具

• 提供簡易的套件定義 package.ini

• 可快速打包成 PEAR 套件

• 可 Bundle 安裝 PEAR 套件 (like Ruby Bundler)

http://github.com/c9s/Onion

Monday, January 14, 13

PHP 版本環境⼯工具

Monday, January 14, 13

phpbrewhttp://github.com/c9s/phpbrew

Monday, January 14, 13

phpbrew

• 取材⾃自 @gugod perlbrew

http://github.com/c9s/phpbrew

Monday, January 14, 13

phpbrew

• 取材⾃自 @gugod perlbrew

• 易於切換 PHP 相關版本

http://github.com/c9s/phpbrew

Monday, January 14, 13

phpbrew

• 取材⾃自 @gugod perlbrew

• 易於切換 PHP 相關版本

• 提供 variant 建置選項 +mysql, +pgsql...etc

http://github.com/c9s/phpbrew

Monday, January 14, 13

phpbrew

• 取材⾃自 @gugod perlbrew

• 易於切換 PHP 相關版本

• 提供 variant 建置選項 +mysql, +pgsql...etc

• 不需 root 權限

http://github.com/c9s/phpbrew

Monday, January 14, 13

phpbrew

• 取材⾃自 @gugod perlbrew

• 易於切換 PHP 相關版本

• 提供 variant 建置選項 +mysql, +pgsql...etc

• 不需 root 權限

• 平台⽀支援: Mac OS X 10.5+, Ubuntu, Debian..

http://github.com/c9s/phpbrew

Monday, January 14, 13

PHP library/app from corneltek

Monday, January 14, 13

PHP Projects• phpbrew

• CLIFramework

• Onion

• Roller Router

• LazyRecord

• ActionKit

• PEARX

• Universal

• FormKit

• ValidationKit

• ClassMap

• GetOptionKit

族繁不及備載...

Monday, January 14, 13

為什麼要重造輪⼦子?

Monday, January 14, 13

設計軟體 != 設計輪⼦子

Monday, January 14, 13

It’s not that simple並⾮非像輪⼦子那樣的簡單

Monday, January 14, 13

軟體有相依性但輪⼦子沒有

Monday, January 14, 13

⼀一旦應⽤用程式相依了他⼈人的框架你的開發模式也將受到侷限

Monday, January 14, 13

開發⼯工具與⼈人息息相關但輪⼦子只需透過輪軸傳動

Monday, January 14, 13

使⽤用他⼈人的 FullStack 框架

Monday, January 14, 13

嘗到的是短期的甜頭

Monday, January 14, 13

犧牲的是未來的無限可能

Monday, January 14, 13

什麼是 FullStack Framework ?

Monday, January 14, 13

就是⼀一整包送給你

Monday, January 14, 13

FullStack Framework

• Rails

• Zend Framework

• Symfony

• WordPress

• Joomla

• etc...

Monday, January 14, 13

FW 1.0

使⽤用⼀一個架構快速⼤大幅修改的框架

Monday, January 14, 13

FW 1.0

App A

使⽤用⼀一個架構快速⼤大幅修改的框架

這個 FW 好像不錯來⽤用⽤用看

Monday, January 14, 13

FW 1.0 FW 2.0

App A

使⽤用⼀一個架構快速⼤大幅修改的框架

Monday, January 14, 13

FW 1.0 FW 2.0

App A App B

使⽤用⼀一個架構快速⼤大幅修改的框架

2.0 有個功能 X 實在太棒了,趕快來⽤用

改太多沒時間升級啦不管了

Monday, January 14, 13

FW 1.0 FW 2.0 FW 3.0

App A App B

使⽤用⼀一個架構快速⼤大幅修改的框架

Monday, January 14, 13

FW 1.0 FW 2.0 FW 3.0

App A App B

使⽤用⼀一個架構快速⼤大幅修改的框架

相依於 FW2.0 的 X 功能但 FW3.0 卻拿掉了 X

Migration is hard!

Monday, January 14, 13

FW 1.0 FW 2.0 FW 3.0

App A App B

使⽤用⼀一個架構快速⼤大幅修改的框架

App C

無形之中增加的維護成本怕跟不上潮流,於是新網站⼜又使⽤用 FW 3.0

Monday, January 14, 13

FW 1.0 FW 2.0 FW 3.0 bug fix security fix

App A App B

使⽤用⼀一個架構快速⼤大幅修改的框架

App C

新的修正只適⽤用新的版本但由於架構⼤大幅修改,同樣的 patch 無法直接套⽤用於 FW 2.0 的 App B,只能⼿手動修改

bug fix security fix

Monday, January 14, 13

使⽤用 FullStack 框架之侷限

Monday, January 14, 13

使⽤用 FullStack 框架之侷限• 隨著框架不斷修改內建⾏行為, 升級的過程,就會有越多不確定因素(bug, security)

Monday, January 14, 13

使⽤用 FullStack 框架之侷限• 隨著框架不斷修改內建⾏行為, 升級的過程,就會有越多不確定因素(bug, security)

• 網站規模越⼤大,升級越苦。

Monday, January 14, 13

使⽤用 FullStack 框架之侷限• 隨著框架不斷修改內建⾏行為, 升級的過程,就會有越多不確定因素(bug, security)

• 網站規模越⼤大,升級越苦。• 功能開發及系統效能會因為框架⽽而有所限制。

Monday, January 14, 13

Allen Own 不安定因素

Monday, January 14, 13

Allen Own 不安定因素

Monday, January 14, 13

So how do we do that?

Monday, January 14, 13

Divide and Conquer

Monday, January 14, 13

Framework should just be “framework”

Monday, January 14, 13

Components should be easy to adapt/swap

Monday, January 14, 13

Each component should have a package state

- API stability-Package stability

Monday, January 14, 13

Framework

Component A

Component B

Component C

The core is pretty small, we don’t need to change

core API frequently

Monday, January 14, 13

Framework

Component A 2.0

Component B

Component C

API LockStable

API LockBeta Stability

API BetaBeta Stability

API LockStable

Monday, January 14, 13

Framework

Component A 2.0

Component B

Component C

API LockStable

API LockBeta Stability

API BetaBeta Stability

Framework BNew Concept

API LockStable

We can build another new framework very easily.

Monday, January 14, 13

How do we build CLI applications?

Monday, January 14, 13

CLIFrameworkhttps://github.com/c9s/CLIFramework

Monday, January 14, 13

CLIFramework

• 提供最快最簡易的⽅方式建置⼀一個命令列的⼯工具

• phpbrew, onion, classmap ... etc

Monday, January 14, 13

CLIFramework

⽀支持⼦子命令及⼦子命令選項

Monday, January 14, 13

CLIFramework<?phpnamespace TestApp\Command;use CLIFramework\Command;class ListCommand extends Command { function execute($arg1,$arg2) { // .. do something here... }}

Monday, January 14, 13

CLIFramework<?phpnamespace YourApp;use CLIFramework\Application;

class CLIApplication extends Application{

/* init your application options here */ function options($opts) { $opts->add('v|verbose', 'verbose message'); $opts->add('path:', 'required option with a value.'); $opts->add('path?', 'optional option with a value'); $opts->add('path+', 'multiple value option.'); }

/* register your command here */ function init() { $this->registerCommand( 'list', '\YourApp\Command\ListCommand' ); $this->registerCommand( 'foo', '\YourApp\Command\FooCommand' ); }}

Monday, January 14, 13

CLIFramework

<?php

$app = new \TestApp\Application;$app->run($argv);

Monday, January 14, 13

CLIFramework

⾃自動產⽣生的 Command-line help

Monday, January 14, 13

How do we generate forms?

Monday, January 14, 13

FormKithttps://github.com/c9s/FormKit

Monday, January 14, 13

FormKit

• A powerful form widget generator.

• Simple API for defining widgets and layout.

• Customizable layout engine.

Monday, January 14, 13

FormKit: TextInput

<?php$text = new FormKit\Widget\TextInput('username', array( 'label' => 'Username', 'placeholder' => 'Your name please', 'hint' => 'Please enter 6 characters for your username',));$text->value( 'default' ) ->size(20);echo $text; // render

Monday, January 14, 13

FormKit<?php$countries = new FormKit\Widget\SelectInput( 'country' , array( 'label' => 'Country', 'options' => array( 'Test' => 'Test', 'Asia' => array( 'Taiwan', 'Taipei', 'Tainan', 'Tokyo', 'Korea', ) )));

Monday, January 14, 13

FormKit: GenericLayout<?php$layout = new FormKit\Layout\GenericLayout;$layout->width(400);$layout->addWidget( $text ) ->addWidget( $password ) ->addWidget( $remember ) ->addWidget( $birthday ) ->addWidget( $best_time ) ->addWidget( $role ) ->addWidget( $size ) ->addWidget( $countries ) ->cellpadding(6) ->cellspacing(6) ->border(0);echo $layout;

Monday, January 14, 13

FormKit: Helpers

<?phpuse FormKit\FormKit;$username = FormKit::text('username');$password = FormKit::password('password',array( 'class' => 'your-element-class-name', 'id' => 'your-element-id', 'value' => 'default password',));echo $username->render();echo $password->render();

Monday, January 14, 13

Available Widgets• TextareaInput

• TextInput

• ButtonInput

• CheckboxInput

• ColorInput

• DateInput

• DatetimeInput

• FileInput

• HiddenInput

• Label

• PasswordInput

• RadioInput

• ResetInput

• SelectInput

• SubmitInput

• AjaxCompleteInput

• CanvasInput

Monday, January 14, 13

For more detailshttp://github.com/c9s/FormKit

Monday, January 14, 13

How do we define logics for forms?

Monday, January 14, 13

ActionKithttps://github.com/c9s/ActionKit

Monday, January 14, 13

ActionKit

• Let you define logics and form field definitions.

• Use FormKit to render form fields automatically.

Monday, January 14, 13

If I have a login form and login logics

Monday, January 14, 13

<?phpnamespace User\Action;use ActionKit;

class Login extends \ActionKit\Action{ public function scheme() { $this->param("account") ->renderAs("TextInput");

$this->param("password") ->renderAs("PasswordInput");

$this->param("remember_me"); }}

Define your form fields.

Monday, January 14, 13

<?phpnamespace User\Action;use ActionKit;

class Login extends \ActionKit\Action{ public function scheme() { $this->param("account") ->renderAs("TextInput");

$this->param("password") ->renderAs("PasswordInput");

$this->param("remember_me"); }

public function run() { $account = $this->arg('account'); $password = $this->arg('password');

/* your login logics here */

return $this->success('Login successfully'); }}

Define your logics here.

Monday, January 14, 13

ActionKit: The API

<?php$action = new User\Action\Login;echo $action->createView()->render();

// customized action layout.echo $action->createView("CustomziedLayoutClass")->render();

Render the form.

Monday, January 14, 13

ActionKit: The API

<?php$runner = ActionKit\ActionRunner::getInstance();$runner->registerAutoloader();

$result = $runner->run("User\\Action\\Login");if( $result && $runner->isAjax() ) { // JSON header('Content-Type: application/json; Charset=utf-8'); echo $result->__toString(); exit(0);}

Handle the logics and return the result.

Monday, January 14, 13

How do we dispatch URL?

Monday, January 14, 13

Roller Routerhttps://github.com/c9s/Roller

Monday, January 14, 13

Roller Router• A fast router for PHP.

Monday, January 14, 13

Roller Router• A fast router for PHP.

• Designed for performance.

Monday, January 14, 13

Roller Router• A fast router for PHP.

• Designed for performance.

• Let you define plugins, routes easily.

Monday, January 14, 13

Roller Router• A fast router for PHP.

• Designed for performance.

• Let you define plugins, routes easily.

• APC / File Cache.

Monday, January 14, 13

Roller Router• A fast router for PHP.

• Designed for performance.

• Let you define plugins, routes easily.

• APC / File Cache.

• Annotation Reader support.

Monday, January 14, 13

Roller Router• A fast router for PHP.

• Designed for performance.

• Let you define plugins, routes easily.

• APC / File Cache.

• Annotation Reader support.

• RESTful plugin

Monday, January 14, 13

Roller Router• A fast router for PHP.

• Designed for performance.

• Let you define plugins, routes easily.

• APC / File Cache.

• Annotation Reader support.

• RESTful plugin

• With C Extension support.

Monday, January 14, 13

Roller Router<?php$router = new Roller\Router( null, array( 'cache_id' => 'router_demo'));

Monday, January 14, 13

Roller Router<?php$router = new Roller\Router( null, array( 'cache_id' => 'router_demo'));$router->add( '/:id/:name' , function($id,$name) { return sprintf('Hello %s, %d', $name, $id);});

Monday, January 14, 13

Roller Router<?php$router = new Roller\Router( null, array( 'cache_id' => 'router_demo'));$router->add( '/:id/:name' , function($id,$name) { return sprintf('Hello %s, %d', $name, $id);});

$r = $router->dispatch( $_SERVER['PATH_INFO'] );if( $r !== false ) echo $r();else die('page not found.');

Monday, January 14, 13

Roller: Add routes

<?php$router->add( '/posts/:id', array('PostController','readPostAction') );

Monday, January 14, 13

Roller with DSL

<?phprequire 'bootstrap.php';require 'Roller/DSL.php';

on('/path',function() { return 'your content';});

on('/path/to/:year', [ ':year' => '\d+' ] ,function() { return 'your content';});

dispatch( $_SERVER['PATH_INFO'] );

Monday, January 14, 13

One more thing!

Monday, January 14, 13

If you’re using PHP5.4+

Monday, January 14, 13

You can even use the built-in HTTP server.

Monday, January 14, 13

Roller Router

<?phpif (php_sapi_name() == 'cli-server') { $uri = $_SERVER['REQUEST_URI']; $info = parse_url($uri); if (preg_match('/\.(?:png|jpg|jpeg|gif|js|css)$/', $info['path'] )) return false; // serve the requested resource as-is. $path = ltrim($info['path'],'/'); if( file_exists($path) ) return false; $pathinfo = $info['path'];} else { $pathinfo = isset($_SERVER['PATH_INFO']) ? $_SERVER['PATH_INFO'] : '/';}

... $router here

Monday, January 14, 13

$ php -S localhost:8888 router.php

Monday, January 14, 13

How about RESTful?

Monday, January 14, 13

Roller + RESTful<?php

class MyGenericHandler extends Roller\Plugin\RESTful\GenericHandler{

public function create($resource) { return array( 'id' => 99 ); }

public function load($resource,$id) { return array( 'id' => $id ); }

public function update($resource,$id) { $put = $this->parseInput(); return $put; }

public function delete($resource,$id) { $args = $this->parseInput(); // print_r($args); return array( 'id' => $id ); }

public function find($resource) { return range(1,10); }}

Monday, January 14, 13

Mount your RESTful handler

$restful = new Roller\Plugin\RESTful(array( 'prefix' => '/=' ));$restful->setGenericHandler( 'MyGenericHandler' );

$router->addPlugin($restful);

GET http://localhost:8888/=/book/1POST http://localhost:8888/=/book

Monday, January 14, 13

For more detailshttp://github.com/c9s/Roller

Monday, January 14, 13

LazyRecordhttps://github.com/c9s/Roller

Monday, January 14, 13

A Fast PHP ORM

Monday, January 14, 13

Why another PHP ORM ?

Monday, January 14, 13

PHP ORMs

• Doctrine

Monday, January 14, 13

PHP ORMs

• Doctrine

• Propel

Monday, January 14, 13

PHP ORMs

• Doctrine

• Propel

• Idiorm / Paris

Monday, January 14, 13

Propel / Doctrine

• Propel uses XML Schema file.

Monday, January 14, 13

Propel / Doctrine

• Propel uses XML Schema file.

• Doctrine uses XML/YAML/Annotations.

Monday, January 14, 13

Propel / Doctrine

• Propel uses XML Schema file.

• Doctrine uses XML/YAML/Annotations.

• Slow & Fat.

Monday, January 14, 13

Propel / Doctrine

• Propel uses XML Schema file.

• Doctrine uses XML/YAML/Annotations.

• Slow & Fat.

• Doctrine is too complicated.

Monday, January 14, 13

Common characteristic

Monday, January 14, 13

• XML for configuration file.

• XML for schema file.

• XML for everything.

• Concepts are from Java, too complicated.

Monday, January 14, 13

Propel XML runtime.conf

Monday, January 14, 13

<?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> </mem> </details> </logging> </debugpdo> </propel></config>

Monday, January 14, 13

<?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> </mem> </details> </logging> </debugpdo> </propel></config>

Monday, January 14, 13

Monday, January 14, 13

So we designed an easier ORM

Monday, January 14, 13

LazyRecord

• Lazy attributes.

Monday, January 14, 13

LazyRecord

• Lazy attributes.

• Lazy schema loader.

Monday, January 14, 13

LazyRecord

• Lazy attributes.

• Lazy schema loader.

• Dynamic schema via PHP code

Monday, January 14, 13

LazyRecord

• Lazy attributes.

• Lazy schema loader.

• Dynamic schema via PHP code

• Static schema class generator

Monday, January 14, 13

LazyRecord

• Lazy attributes.

• Lazy schema loader.

• Dynamic schema via PHP code

• Static schema class generator

• SQL Generator for SQLite, MySQL & PgSQL.

Monday, January 14, 13

LazyRecord

• Filter / Canonicalizer support.

Monday, January 14, 13

LazyRecord

• Filter / Canonicalizer support.

• CRUD support via ActionKit.

Monday, January 14, 13

LazyRecord

• Filter / Canonicalizer support.

• CRUD support via ActionKit.

• Form generation via ActionKit.

Monday, January 14, 13

LazyRecord

• Filter / Canonicalizer support.

• CRUD support via ActionKit.

• Form generation via ActionKit.

• Migration support.

Monday, January 14, 13

LazyRecord: Schema<?phpnamespace Todos\Model;use LazyRecord\BaseModel;

class Todo extends BaseModel { function schema($schema) { $schema->column('title') ->varchar(128) ->required() ; $schema->column('description') ->text();

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

$schema->seeds('Todos\Seed'); }}

Monday, January 14, 13

LazyRecord: Model

<?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!";} ActiveRecord Pattern

Monday, January 14, 13

LazyRecord: Collection

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

Collection Iterating

Monday, January 14, 13

LazyRecord: Collection

$authors = new AuthorCollection;$authors->where() ->equal('name','Foo') ->groupBy('name','address');

SQL Conditions via SQLBuilder

Monday, January 14, 13

LazyRecord: Collection

$newAuthors = $authors->filter(function($item) { // do something else})->filter(function($item) { return $item->confirmed;});

Monday, January 14, 13

Powerful features

Monday, January 14, 13

Model Schema -> CRUD Actions ->

Form Layout

Monday, January 14, 13

LazyRecord

Model Schema

Monday, January 14, 13

LazyRecord

Model Schema ⇛ Action

Monday, January 14, 13

LazyRecord

Model Schema ⇛ Action ⇛

CRUD

Monday, January 14, 13

LazyRecord

App::Model::Phone ☚ write once

Monday, January 14, 13

LazyRecord

App::Model::PhoneApp::Model::PhoneCollection

Monday, January 14, 13

LazyRecord

App::Model::PhoneApp::Model::PhoneCollection

App::Action::CreatePhone

Monday, January 14, 13

LazyRecord

App::Model::PhoneApp::Model::PhoneCollection

App::Action::CreatePhoneApp::Action::UpdatePhone

Monday, January 14, 13

LazyRecord

App::Model::PhoneApp::Model::PhoneCollection

App::Action::CreatePhoneApp::Action::UpdatePhoneApp::Action::DeletePhone

Monday, January 14, 13

LazyRecord

App::Model::PhoneApp::Model::PhoneCollection

App::Action::CreatePhoneApp::Action::UpdatePhoneApp::Action::DeletePhone

... or any other actions predefined.

Monday, January 14, 13

LazyRecord

App::Model::PhoneApp::Model::PhoneCollection

App::Action::CreatePhoneApp::Action::UpdatePhoneApp::Action::DeletePhone

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

... or any other actions predefined.

Monday, January 14, 13

Migration

Monday, January 14, 13

2013 年還在⾃自⼰己⼿手動下 SQL 做 migration 嗎?

Monday, January 14, 13

Monday, January 14, 13

Schema Upgrade

Monday, January 14, 13

Monday, January 14, 13

For more detailshttp://github.com/c9s/LazyRecord

http://www.slideshare.net/c9s/lazyrecord-the-fast-orm-for-php

Monday, January 14, 13

Thank youFind me: Twitter: @c9s

Monday, January 14, 13

top related