• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
How to build customizable multitenant web applications - PHPBNL11
 

How to build customizable multitenant web applications - PHPBNL11

on

  • 3,383 views

 

Statistics

Views

Total Views
3,383
Views on SlideShare
3,208
Embed Views
175

Actions

Likes
2
Downloads
62
Comments
0

4 Embeds 175

http://lanyrd.com 110
http://iteman.tumblr.com 47
http://stream.puschkasch.com 11
http://tdpsk.soup.io 7

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

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

    How to build customizable multitenant web applications - PHPBNL11 How to build customizable multitenant web applications - PHPBNL11 Presentation Transcript

    • How to build customizablemultitenant web applications Stephan Hochdörfer, bitExpert AG "Building an application so customizable its the last application youll ever need to build" Harrie Verveer
    • About me Stephan Hochdörfer, bitExpert AG Department Manager Research Labs enjoying PHP since 1999 S.Hochdoerfer@bitExpert.de @shochdoerfer
    • Single Tenancy
    • Developer vs. Businessman
    • Single Tenancy – more customers
    • Single Tenancy – even more customers
    • Where will this lead to?
    • Maintenancenightmare!
    • Single Tenancy Tenant 1 Application Database Hardware
    • Single Tenancy Tenant 1 Tenant 2 Tenant 3 Application Application Application Database Database Database Hardware Hardware Hardware
    • Multi Tenancy Tenant 1 Tenant 2 Tenant 3 Application Database Hardware
    • What should be customizable?
    • What should be customizable? Tenant 1 Tenant 2 Tenant 3 Application Database Hardware
    • What should be customizable? Tenant 1 Tenant 2 Tenant 3 Application Database Hardware
    • Frontend | Branding How to skin an application?
    • Application | Frontend How to skin an application? Remember: It`s a web application!
    • Application | Frontend How to skin an application? HTML
    • Application | Frontend How to skin an application? HTML + CSS
    • Application | Frontend
    • Application | Frontend
    • Application | Frontend
    • Application | Frontend How to customize? <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>My App</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <link rel="stylesheet" type="text/css" href="css/styles/myapp.css" /> </head> <body> </body> </html>
    • Application | Frontend How to customize? <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>My App</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <link rel="stylesheet" type="text/css" href="css/styles/<?php echo $tenant ?>.css" /> </head> <body> </body> </html>
    • Application | Frontend How to customize? <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>My App</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <link rel="stylesheet" type="text/css" href="css/styles/myapp.css" /> <link rel="stylesheet" type="text/css" href="css/styles/<?php echo $tenant ? >.css" /> </head> <body> </body> </html>
    • Application | Frontend Feature driven CSS Wait, there`s more...
    • Application | Frontend Feature driven CSS display: none
    • Application | Frontend Next level...
    • Application | Backend Menubar generation <?php if($user->hasEnabled(Module::ORDERMANAGEMENT)) { if($user->canAccess(OrderManagement::LIST_ORDERS)) { $this->renderLink(OrderManagement::LIST_ORDERS); } if($user->canAccess(OrderManagement::ADD_ORDER)) { $this->renderLink(OrderManagement::ADD_ORDER); } if($user->canAccess(OrderManagement::CANCEL_ORDER)) { $this->renderLink(OrderManagement::CANCEL_ORDER); } }
    • Application | Backend Menubar generation <?php if($tenant->hasModule(Module::ORDERMANAGEMENT) { if($user->hasEnabled(Module::ORDERMANAGEMENT)) { if($user->canAccess(OrderManagement::LIST_ORDERS)) { $this->renderLink(OrderManagement::LIST_ORDERS); } if($user->canAccess(OrderManagement::ADD_ORDER)) { $this->renderLink(OrderManagement::ADD_ORDER); } } }
    • Application | Backend Menubar generation Modularize!
    • Application | Backend Menubar generation Module 1 Module 2 Module 3 register at start up Application core
    • Application | Backend Menubar generation Configuration for tenant 1 Module 1 Module 2 Module 3 register at start up Application core
    • Application | Backend Menubar generation Configuration for tenant 2 Module 1 Module 2 Module 3 register at start up Application core
    • Application | Backend Optimize workflows <?php if(CC == $paymentType) { // handle credit card payment } else if(COD == $paymentType) { // handle cash on delivery payment }
    • Application | Backend Optimize workflows <?php if(CC == $paymentType) { // handle credit card payment for some tenants! if(in_array($tenant->getName(), array(tenant1, tenant2)) { // insert logic here... } } else if(COD == $paymentType) { // handle cash on delivery payment for some tenants! if(in_array($tenant->getName(), array(tenant3)) { // insert logic here... } }
    • Application | Backend Optimize workflows Decouple functionality!
    • Application | Backend Optimize workflows <?php $paymentType = CC; // set via request $payment = PaymentFactory::create($paymentType); $payment->execute($order);
    • Application | Backend Optimize workflows <?php $paymentType = CC; // set via request $payment = PaymentFactory::create($paymentType, $tenant); $payment->execute($order);
    • Application | Backend Optimize workflows How to add custom logic?
    • Application | Backend Custom logic - Subclassing? Abstract Payment CC Payment CCPayment CCPayment Tenant 1 Tenant 2
    • Application | Backend Custom logic Any alternatives?
    • Application | Backend Custom logic Let`s add hooks...
    • Application | Backend Custom logic - Hooks <?php $paymentType = CC; // set via request $payment = PaymentFactory::create($paymentType, $tenant); if($this->paymentPreProcessor instanceof IPaymentPreProcessor) { $this->paymentPreProcessor->run($payment, $tenant, $order); } $payment->execute($order); if($this->paymentPostProcessor instanceof IPaymentPostProcessor) { $this->paymentPostProcessor->run($payment, $tenant, $order); }
    • Application | Backend Custom logic How to set the dependencies?
    • Application | Backend Custom logic Inject the dependencies!
    • Application | Backend Custom logic – Dependency Injection <?xml version="1.0" encoding="UTF-8" ?> <beans xmlns="http://www.bitexpert.de/schema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.bitexpert.de/schema/ http://www.bitexpert.de/schema/bitFramework-beans.xsd"> <bean id="MyApp.Service.Order" class="MyAppServiceOrder.php"> </bean> <bean id="Tenant1.Service.Order" class="MyAppServiceOrder.php"> <property name="paymentPreProcessor" ref="Tentant1.Payment.PaymentValidation" /> </bean> <bean id="Tenant2.Service.Order" class="MyAppServiceOrder.php"> <property name="paymentPreProcessor" ref="Tentant2.Payment.StrictValidation" /> <property name="paymentPostProcessor" ref="Tentant2.Payment.PushOrderToSAP" /> </bean> </beans>
    • Application | Backend Custom logic Any improvements?
    • Application | Backend Custom logic <?php $paymentType = CC; // set via request $payment = PaymentFactory::create($paymentType, $tenant); if($this->paymentPreProcessor instanceof IPaymentPreProcessor) { $this->paymentPreProcessor->run($payment, $tenant, $order); } $payment->execute($order); if($this->paymentPostProcessor instanceof IPaymentPostProcessor) { $this->paymentPostProcessor->run($payment, $tenant, $order); }
    • Application | Backend Custom logic <?php $paymentType = CC; // set via request $payment = PaymentFactory::create($paymentType, $tenant); if($this->paymentPreProcessor instanceof IPaymentPreProcessor) { $this->paymentPreProcessor->run($payment, $tenant, $order); } $payment->execute($order); if($this->paymentPostProcessor instanceof IPaymentPostProcessor) { $this->paymentPostProcessor->run($payment, $tenant, $order); }
    • Application | Backend Custom logic Aspect-oriented programming
    • Application | Backend Custom logic – Aspects for the masses! /** * @aspect */ class CustomPaymentProcessingAspect { /** * @around MyAppServiceOrder->processPayment */ public function customFilter(AOPJoinPointInterface $joinPoint) { // @TODO: implement pre-processing logic // ... $result = $joinPoint->getAdviceChain()->proceed($joinPoint); // @TODO: implement post-processing logic // ... return $result; } }
    • Application | Backend Custom logic - Result <?php $paymentType = CC; // set via request $payment = PaymentFactory::create($paymentType, $tenant); $payment->execute($order);
    • Application | Backend Next level...
    • Database Database – Where to store the data?
    • Database Database – Where to store the data? We need to store data for a tenant!
    • Database Database – Where to store the data? Database per Tenant?
    • Database Database – Where to store the data? Database per Tenant? Schema per Tenant?
    • Database Database – Where to store the data? Database per Tenant? Schema per Tenant? Tenant Id per Row?
    • Database Database – How to access the data? vs. ORM dynamic statements
    • What`s beyond? Generalize you should!
    • What`s beyond? Multi Tenancy Software system family
    • What`s beyond? No single solution!
    • What`s beyond? A factory for mass production!
    • What`s beyond? Multi Tenancy – Single Instance Tenant 1 Tenant 2 Tenant 3 Application Database Hardware
    • What`s beyond? Multi Tenancy – Multi Instance Tenant 1 Tenant 2 Tenant 3 Application Database Hardware
    • What`s beyond? Generative Programming Configuration Configuration 1 ... n Implementation Implementation Generator Product components Generator Product components Generator Generator application application
    • What`s beyond? Generative Programming Configuration Configuration Tenant 1 Tenant 1 Implementation Implementation Generator components Generator components Tenant x Tenant x Generator Generator application application
    • What`s beyond? Generative Programming - Goal Create an optimized application!
    • What`s beyond? Generative Programming - Goal Create an optimized application for one tenant!
    • What`s beyond? Generative Programming – Bonus points Reduce application complexity
    • What`s beyond? Generative Programming – Bonus points FileFrm FILEOrderService_php5 { private String PreProcessor = ""; private String PostProcessor = ""; public FILEOrderService_php5() { setFilename("Order.php5"); setRelativePath("/classes/MyApp/Service"); } private void assign() { BEGINCONTENT() <?php $paymentType = CC; // set via request $payment = PaymentFactory::create($paymentType, $tenant); <!{PreProcessor}!> $payment->execute($order); <!{PostProcessor}!> ENDCONTENT() } }
    • What`s beyond? Generative Programming – Bonus points FileFrm FILEOrderService_php5 { [...] private void configure() { if(this.getConfiguration().hasFeature(PreProcessor)) { PreProcessor = this.getPreProcessorContent( this.getConfiguration.getTenant() ); } if(this.getConfiguration().hasFeature(PostProcessor)) { PostProcessor = this.getPostProcessorContent( this.getConfiguration.getTenant() ); } } }
    • Application | Backend Generative Programming – Bonus points Example: Preprocessor: Postprocessor: Output:
    • Application | Backend Generative Programming – Bonus points Example: Preprocessor: Postprocessor: Output: <?php $paymentType = CC; // set via request $payment = PaymentFactory::create($paymentType); $payment->execute($order);
    • Application | Backend Generative Programming – Bonus points Example: Preprocessor: $this->paymentPreProcessor->run($payment, $tenant, $order); Postprocessor: Output:
    • Application | Backend Generative Programming – Bonus points Example: Preprocessor: $this->paymentPreProcessor->run($payment, $tenant, $order); Postprocessor: Output: <?php $paymentType = CC; // set via request $payment = PaymentFactory::create($paymentType); $this->paymentPreProcessor->run($payment, $tenant, $order); $payment->execute($order);
    • What`s beyond? Generative Programming – Bonus points Reduce maintenance support
    • What`s beyond? Generative Programming – Bonus points Implementation Feature component
    • What`s beyond? Generative Programming – Bonus points Feature Implementation component
    • What`s beyond? Generative Programming – Bonus points Customer Feature Implementation component
    • What`s beyond? Generative Programming – The book
    • http://joind.in/2497
    • Flickr Creditshttp://www.flickr.com/photos/andresrueda/3452940751/http://www.flickr.com/photos/andresrueda/3455410635/