• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
Bullet: The Functional PHP Micro-Framework
 

Bullet: The Functional PHP Micro-Framework

on

  • 17,219 views

 

Statistics

Views

Total Views
17,219
Views on SlideShare
17,178
Embed Views
41

Actions

Likes
1
Downloads
9
Comments
0

3 Embeds 41

https://twitter.com 20
http://0.0.0.0 11
http://librosweb.es 10

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

CC Attribution License

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    Bullet: The Functional PHP Micro-Framework Bullet: The Functional PHP Micro-Framework Presentation Transcript

    • Bullet: The Functional PHP Micro-Framework Vance Lucas • Co-Founder, Brightbit http://bulletphp.com
    • Who are You? • Vance Lucas • http://vancelucas.com • @vlucas (for heckling) • PHP since 1999 (PHP3) • Brightbit • http://brightbit.com • Design, Development & Consulting for web apps, mobile apps and APIs
    • History & Philosophy (Don't worry, it won't be as boring as school was)
    • MVC Frameworks • I’ve created LOTS of MVC frameworks. • They all sucked. • Except maybe one. • Alloy Framework • Released Feb. 2011 • But it’s dead to me now…
    • “The same thing, only different”
    • “Lightweight” “Flexible” “Fast” “Simple” “Modular” “Artisan”
    • “The fool hath said in his heart, There is no better architectural pattern than MVC” * may not be exact quote
    • “I don't like MVC because that's not how the web works. Symfony2 is an HTTP framework; it is a Request/Response framework. That's the big deal.” Fabien Potencier http://fabien.potencier.org/article/49/what-is-symfony2 October 25, 2011
    • Philosophy • Do more with less (code) • Low cognitive overhead/complexity • Embrace HTTP • Leverage raw PHP without introducing too many “framework concepts” • Only PHP knowledge should be enough • Shouldn’t have to “fight the framework” • “Micro” != No Structure
    • “SharedEventManager” “PluginBroker” “RouteStack” “TemplateMapResolver” “AggregateResolver” “DefaultListenerAggregate” “RouteNotFoundStrategy” “TemplatePathStack”
    • What is Bullet? Well, it’s a Micro-framework for starters…
    • Main Concepts • Micro-framework • URL Routing, Request, Response, Templates • Built around HTTP and defined URIs • Parses one URI segment at a time • Declarative, functional-style nested routing • Leverages closures for structure and scope • Less repetitive code, cleaner routes
    • Guiding Rules • Only one path segment at a time, and only Closures can be used • Response must be explicitly returned • Path must be fully consumed (or error) • Handlers for different behavior: • Path, Param, Method, Format • Method and format handlers only run when path has been fully consumed
    • Show me some code! ! GET /posts/42
    • // Bullet index file! define('BULLET_ROOT', dirname(__DIR__));! define('BULLET_APP_ROOT', BULLET_ROOT . '/app/');! define('BULLET_SRC_ROOT', BULLET_APP_ROOT . '/src/');! ! // Composer Autoloader! $loader = require BULLET_ROOT . '/vendor/autoload.php';! ! // Bullet App! $app = new BulletApp(require BULLET_APP_ROOT . 'config.php');! $request = new BulletRequest();! ! // Common include! require BULLET_APP_ROOT . '/common.php';! ! // Require all paths/routes! $routesDir = BULLET_APP_ROOT . '/routes/';! require $routesDir . 'index.php';! require $routesDir . 'posts.php';! require $routesDir . 'events.php';! require $routesDir . 'users.php';! ! // Response! echo $app->run($request);
    • Bullet Routing $app->path('posts', function($req) {! // Param! $this->param('int', function($req, $id) {! $post = Post::find($id);! check_user_acl_for($post);! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! });! }); // Method! $this->get(function($req) use($post) {! // Format! ! ! $this->format('json', function() use($post) {! ! ! ! ! return $post->toArray();! ! ! });! ! ! $this->format('html', function() use($post) {! ! ! ! ! return $this->template('html', …);! ! ! });! });!
    • Quick Code Comparison
    • Typical Micro-Framework $app->get('/posts/:id', function($id) use($app) {! $post = Post::find($id);! check_user_acl_for($post);! ! if(is_json()) {! header("Content-Type: application/json");! echo json_encode($result);! exit;! }! ! $app->render('posts/view', compact('post'));! });!
    • Typical MVC Controller class BlogController extends BaseController {! public function getView($slug)! {! // Get this blog post data! $post = $this->post->where('slug', '=', $slug)->first();! ! ! // Check if the blog post exists! if (is_null($post)) {! return App::abort(404);! }! // Show the page! return View::make('site/blog/view_post', compact('post', 'comments', 'canComment'));! }! }
    • Bullet Closure Context $app->path('posts', function($req) {! $this->param('int', function($req, $id) {! $post = Post::find($id);! check_user_acl_for($post);! ! // View (GET)! $this->get(function($req) use($post) {! // ...! });! ! // Delete! $this->delete(function($req) use($post) {! $post->delete();! // ...! });! });! });
    • Bullet Route Handlers
    • Path Handlers $app->resource('posts', function($request) {! // ...! });! ! $app->path('posts', function($request) {! // ...! });! ! $app->path(['posts', 'articles'], function($req) {! // ...! });
    • Path Handlers • Return 404 File Not Found if request path not found • Can be nested as deep as you want • /admin/articles/3/comments
    • Param Handlers $app->param('int', function($request, $id) {! // ...! });! ! $app->param('slug', function($request, $slug) {! // ...! });! ! // CUSTOM alphanumeric handler (returns boolean)! $app->registerParamType('alphanum',function($value) {! return ctype_alnum($value);! });! $app->param('alphanum', function($request, $alnum) {! // ...! });
    • Param Handlers • Test function • true or scalar value executes route • false skips route • Value passed in as extra parameter to handler closure
    • Method Handlers $app->resource('articles', function($request) {! $this->get(function($request) {! // ...! });! ! $this->post(function($request) {! // ...! });! ! $this->delete(function($request) {! // ...! });! });
    • Method Handlers • Return 405 Method Not Allowed if request method not found
    • Format Handlers $app->resource('articles', function($request) {! $this->get(function($request) {! $this->format(‘json', function($request) {! // ...! });! $this->format(‘html', function($request) {! // ...! });! });! });
    • Format Handlers • Return 406 Not Acceptable if request format not found
    • Other Handlers $app->domain(‘vancelucas.com', function($request) {! // ...! });! ! $app->subdomain(‘api', function($request) {! // ...! });
    • Return Types • String (“hello world”) • Integer (201 - Sends HTTP status code) • Boolean False (404 error) • Array (auto json_encode + headers) • BulletResponse instance • Custom obj. (w/custom response handler)
    • Building the URL you want should be easy
    • $app->path('admin', function($req) use($app) {! some_acl_check__that_throws_exception_if_not();! ! require 'posts.php'; // For /admin/posts ...! require 'events.php'; // For /admin/events ...! require 'comments.php'; // For /admin/comments ...! });
    • …And Links Too // RELATIVE url! // /posts/25/comments/57,! // /events/9/comments/57,! // /comments/57! echo $app->url('./comments/' . $comment->id);! ! // ROOT url (always /comments/57)! echo $app->url('/comments/' . $comment->id);!
    • Recommended Setup http://bulletphp.com/docs/organization/
    • Events • Global: ‘before’, and ‘after’ • Dynamic • [http_status_code] - 404, 500, etc. • [response_format] - json, html, etc. • [exception_class] - exception class name like “InvalidArgumentException” or just “Exception” to catch all exceptions
    • HTTP Error Handling $app->on(404, function($req, $res){! $response->content($app->template('errors/404'));! });!
    • Exception Handling $app->on('Exception', function($req, $res, Exception $e) {! if($req->format() === 'json') {! $data = array(! 'exception' => get_class($e),! 'message' => $e->getMessage()! );! if(BULLET_ENV !== 'production') {! $data['file'] = $e->getFile();! $data['line'] = $e->getLine();! $data['trace'] = $e->getTrace();! }! ! } else {! $data = $app->template('errors/exception', ['e' => $e]);! }! $res->content($data);! });!
    • Nested Sub Requests $app = new BulletApp();! $app->path('foo', function($request) {! return "foo";! });! $app->path('bar', function($request) {! $res = $this->run('GET', '/foo'); // `BulletResponse`! return $res->content() . 'bar';! });! echo $app->run('GET', 'bar'); // output => 'foobar'!
    • Getting Started http://bulletphp.com ! https://github.com/vlucas/bulletphp ! Skeleton App (basic setup / starting point) https://github.com/vlucas/bulletphp-skeleton ! Obligatory blog example https://github.com/vlucas/bulletphp-blog-example
    • MVC Framework Anti-Patterns Some more controversial than others
    • “REST Controller” vs “Base Controller”
    • Can’t use basic PHP knowledge to change the flow of your application
    • ! $this->forward('someOtherAction' . $params);!
    • $this->beforeFilter('auth', array(! 'except' => 'getLogin'! ));!
    • /:controller/:action/:id
    • $response->setStatusCode(Response::HTTP_NOT_FOUND);! ! class Response {! // ...! const HTTP_CONTINUE = 100;! const HTTP_SWITCHING_PROTOCOLS = 101;! const HTTP_PROCESSING = 102;! const HTTP_OK = 200;! const HTTP_CREATED = 201;! const HTTP_ACCEPTED = 202;! const HTTP_NON_AUTHORITATIVE_INFORMATION = 203;! const HTTP_NO_CONTENT = 204;! // ...! }! HttpFoundation Component Docs Symfony/Component/HttpFoundation/Response.php
    • class Response {! // ...! const STATUS_CODE_CUSTOM = 0;! const STATUS_CODE_100 = 100;! const STATUS_CODE_101 = 101;! const STATUS_CODE_102 = 102;! const STATUS_CODE_200 = 200;! const STATUS_CODE_201 = 201;! const STATUS_CODE_202 = 202;! const STATUS_CODE_203 = 203;! const STATUS_CODE_204 = 204;! // ...! }! Zend Framework 2 - Zend/Http/Response.php
    • Classes for Controllers
    • Questions? @vlucas | vance@vancelucas.com ! ! Rate this talk! https://joind.in/10434