Save 37% off PRO during our Black Friday Sale! »

A resource orientated framework using the DI/AOP/REST Triangle

A resource orientated framework using the DI/AOP/REST Triangle

DI, AOP and REST are powerful patterns that developers should have in their tool belts. Akihito’s open source BEAR.Sunday framework goes one step further and uses them as the basis for strong architectural design for large scale PHP applications.
With very few components of its own, BEAR.Sunday is a fantastic example of how a framework can be built using existing components and libraries from other frameworks, yet offer even further simplicity beauty and power by holding on to these 3 core design patterns.

phpnw13
http://conference.phpnw.org.uk/phpnw13/schedule/akihito-koriyama-richard-mcintyre/

joindin
http://joind.in/talk/view/9302

Aad26cd7119bd8c0c2bbea107515716d?s=128

Akihito Koriyama

October 06, 2013
Tweet

Transcript

  1. A resource orientated framework using the DI /AOP/REST Triangle

  2. About Us • Akihito Koriyama • A Tokyo based freelance

    PHP architect • BEAR.Sunday lead, Aura PHP member • Richard McIntyre • Manchester / leeds based freelance PHP developer • BEAR.Sunday contributor, Lithium member
  3. About Us • Akihito Koriyama • A Tokyo based freelance

    PHP architect • BEAR.Sunday lead, Aura PHP member • Richard McIntyre • Manchester / Leeds based freelance PHP developer • BEAR.Sunday contributor, Lithium member
  4. None
  5. BEAR.Sunday is an application framework. But it offers no libraries.

    (We have good stuff)
  6. instead, it offers three object frameworks.

  7. What is a framework ?

  8. “imposes a set of design constraints on end-user code.”

  9. None
  10. None
  11. 3.hypermedia framework

  12. DI AOP REST

  13. DI Benefits • Dependency Inversion Principle • Clear separation of

    object instantiation and object usage • Object delivery
  14. DIP • Code should depend on things that are at

    the same or higher level of abstraction • High level policy should not depend on low level details
  15. “The principle of dependency inversion is at the root of

    many of the benefits claimed for object- oriented technology. Its proper application is necessary for the creation of reusable frameworks”
  16. Ray.DI Dependency Injection Framework

  17. /** * @Inject */ public function __construct(RenderInterface $renderer) { ...

    1.annotate at injection point class RendererModule extends AbstractModule { protected function configure() { $this->bind('RenderInterface') ->to('HalRenderer') ->in(Scope::SINGLETON); } $injector = Inject::create([new RendererModule]]; 2 bind abstraction to concretion 3.create an injector
  18. /** * @Inject */ public function __construct(RenderInterface $renderer) { ...

    1.annotate at injection point class RendererModule extends AbstractModule { protected function configure() { $this->bind('RenderInterface') ->to('HalRenderer') ->in(Scope::SINGLETON); } $injector = Inject::create([new RendererModule]]; 2. bind abstraction to concretion 3.create an injector
  19. /** * @Inject */ public function __construct(RenderInterface $renderer) { ...

    1.annotate at injection point class RendererModule extends AbstractModule { protected function configure() { $this->bind('RenderInterface') ->to('HalRenderer') ->in(Scope::SINGLETON); } $injector = Inject::create([new RendererModule]]; 2 bind abstraction to concretion 3.create an injector
  20. $user = $injector->getInstance('UserInterface'); 4. Get an object graph from the

    $injector User Renderer Renderer Interface depends A B
  21. QSPDFEVSBM PCKFDUPSJFUOFE DPNQJMBUJPO SVOUJNF Implement the structure, not a procedure

  22. class RendererModule extends AbstractModule { protected function configure() { $this

    ->bind('RenderInterface') ->to('HalRenderer') ->in(Scope::SINGLETON); } } Only use concrete classes in compilation
  23. Only abstraction in runtime /** * @Inject */ public function

    __construct(RenderInterface $renderer) {
  24. DI Best practice “Your code should deal directly with the

    Injector as little as possible. Instead, you want to bootstrap your application by injecting one root object.”
  25. Application = one root object

  26. Application class

  27. None
  28. Application is root object retrieved with injector: $injector = Injector::create([new

    AppModule($context)]]; $app = $injector->getInstance(‘AppInterface’);
  29. Application has dependency.

  30. None
  31. Dependencies have other dependencies Each object either contains or belongs

    to.
  32. You get a application object graph. huge, but can be

    stored one single root value $app
  33. "QQMJDBUJPODBOCFTFSJBMJ[FE $app can be serialized and stored Injection is reused

    beyond requests.
  34. $app Object i/f i/f Object i/f i/f Object Router Response

    JSON XM L 1st framework: DI Framework • annotations based DI framework w/ binding DSL • compilation / runtime separation • use only “plug/abstraction” at runtime • application a single large cached object • focus on structure not behavior
  35. Aspect Oriented Programing

  36. What is AOP? Cache Log Auth A programming paradigm that

    aims to increase modularity by allowing the separation of cross-cutting concerns
  37. /** * @Cache */ public function onGet($id) { // ...

    $this->body = $stmt->fetchAll(PDO::FETCH_ASSOC); return $this; } class Post extends AppModel { public function newest() { $result = Cache::read('newest_posts', 'longterm'); if (!$result) { $result = $this->find('all'); Cache::write('newest_posts', $result, 'longterm'); } return $result; } }
  38. M C I I AOP

  39. M C Cache Cache is called by method invocation, If

    the cache is warm the model is never called. $obj->read(2); Miss !
  40. Aspects Core Concern Cross Cutting Concern Separation

  41. Rock Concert Example

  42. interface MethodInterceptor { public function invoke(MethodInvocation $invocation); } $invocation->proceed(); //

    invoked method $object = $invocation->getThis(); // get source object $args = $invocation->getArgs(); // get arguments
  43. class Transactional implements MethodInterceptor { public function invoke(MethodInvocation $invocation) {

    $object = $invocation->getThis(); $ref = new ReflectionProperty($object, 'db'); $ref->setAccessible(true); $db = $ref->getValue($object); $db->beginTransaction(); try { $invocation->proceed(); $db->commit(); } catch (Exception $e) { $db->rollback(); } } } `Transactional`interceptor Core Concern Cross Cutting Concern
  44. class CacheInterceptor implements MethodInterceptor { public function invoke(MethodInvocation $invocation) {

    $obj = $invocation->getThis(); $args = $invocation->getArguments(); $id = get_class($obj) . serialize($args); $saved = $this->cache->fetch($id); if ($saved) { return $saved; } $result = $invocation->proceed(); $this->cache->save($id, $result); return $result; } } `Cache`interceptor Core Concern Cross Cutting Concern
  45. 4JNQMZBOOPUBUF UIFODSFBUFZPVSCJOEJOH #JOE

  46. Layering by context • MVC, Is 3 enough ?

  47. API Client

  48. API Log Client Valid Auth

  49. API Log !7BMJE BENJO %&-&5& Client Valid Auth

  50. Aspect layering by context Model Cache Form Transaction Auth Validation

  51. <?php class SandboxResourcePageIndexRay0000000071f9ab280000000033fb446fAop extends Sandbox\Resource\Page\Index implements Ray\Aop\WeavedInterface { private $rayAopIntercept

    = true; public $rayAopBind; public function onGet() { // native call if (!isset($this->rayAopBind[__FUNCTION__])) { return call_user_func_array('parent::' . __FUNCTION__, func_get_args()); } // proceed source method from interceptor if (!$this->rayAopIntercept) { $this->rayAopIntercept = true; return call_user_func_array('parent::' . __FUNCTION__, func_get_args()); } // proceed next interceptor $this->rayAopIntercept = false; $interceptors = $this->rayAopBind[__FUNCTION__]; $annotation = isset($this->rayAopBind->annotation[__FUNCTION__]) ? $this->rayAopBind >annotation[__FUNCTION__] : null; $invocation = new \Ray\Aop\ReflectiveMethodInvocation(array($this, __FUNCTION__), func_get_args(), $interceptors, $annotation); return $invocation->proceed(); } Under the hood: Method interception sub class is created in order enable this interception and keep type safety.
  52. Runtime injection by aspect • method / parameter lookup •

    test friendly
  53. 2nd framework: Aspect Oriented Framework • AOP alliance standard •

    Layering by context • Type safe • Runtime injection
  54. None
  55. Hypermedia framework for object as a service It allows objects

    to have RESTful web service benefits such as client-server, uniform interface, statelessness, resource expression with mutual connectivity and layered components.
  56. class Author extends ResourceObject { public $code = 200; public

    $headers = []; public $body = []; /** * @Link(rel="blog", href="app://self/blog/post?author_id={id}") */ public function onGet($id) { ... // change own state return $this; } public function onPost($name) { $this->code = 201; // created return $this; } public function onPut($id, $name)
  57. $user = $resource ->get ->uri('app://self/user') ->withQuery(['id' => 1]) ->eager ->request();

    var_dump($user->body); // Array // ( // [name] => John // [age] => 15 //) echo $user; // <div id=”name”>John</div> // <div id=”age”>15</div> public function onGet($id) { $this[‘name’] = ‘John’; $this[‘age’] = 15; return $this; } User Profile Friend
  58. $order = $resource ->post ->uri('app://self/order') ->withQuery(['drink' => 'latte']) ->eager ->request();

    $payment = [ 'credit_card_number' => '123456789', 'expires' => '07/07', 'name' => 'Koriym', 'amount' => '4.00' ]; // Now use a hyperlink to pay $response = $resource->href('pay', $payment); echo $response->code; // 201 Hypermedia as the Engine of Application State
  59. class Order extends ResourceObject { /** * * @Link(rel="pay", method="put",

    href="app://self/payment{?order_id,card_number,amount}") */ public function onPost($drink) { // data store here $this['drink'] = $drink; $this['order_id'] = $orderId; // created $this->code = 201; return $this; } Hypermedia as the Engine of Application State
  60. Order Payment hyper reference: pay HyperMedia Driven API

  61. The key of success of web • URI • Unified

    Interface • Hyperlink
  62. • API is hub • API is core value API

    driven development DB Mobil e Web API Cloud Moc k URI API API
  63. http://blog.8thlight.com/uncle-bob/2012/08/13/the-clean-architecture.html

  64. Layered Resource UI Mobile Web Page Resource App script App

    Resource Entity
  65. None
  66. None
  67. None
  68. None
  69. Performance • annotation ? dependency injection ? method interception ?

    DSL ? named parameter ? • Fast • cache all compiled object • http friendly architecture
  70. Scale • “model proxy” pattern • ‘app://self/blog/entry’ can be anything.

    • contextual injection makes db scale easy
  71. Hard spot / Soft spot • DI configure hardspot. QFSTZTUFN

    • Aop configure softspot, change on request
  72. Connecting frameworks • DI - object as dependency • AOP

    - domain logic to application logic • Hypermedia - resource to resource
  73. Abstraction frameworks • DSL • Annotation • URI • Interface

    • Aspects • Hypermedia
  74. None
  75. “Zen” framework

  76. Thanks. Arigato http://www.flickr.com/photos/stevehoad/4678289858/ @mackstar @koriym