how to build customizable multitenant web applications - ipc11 spring edition
DESCRIPTION
TRANSCRIPT
How to build customizablemultitenant web applications
Multitenant web applications
About me
Stephan Hochdörfer, bitExpert AG
Department Manager Research Labs
enjoying PHP since 1999
@shochdoerfer
Single Tenancy
Multitenant web applications
Developer vs. Businessman
Multitenant web applications
Single Tenancy – more customers
Multitenant web applications
Single Tenancy – even more customers
Multitenant web applications
Multitenant web applications
Where will this lead to?
Multitenant web applications
Maintenance nightmare!
Single Tenancy
Multitenant web applications
Tenant 1
Application
Database
Hardware
Single Tenancy
Multitenant web applications
Tenant 1
Application
Database
Hardware
Tenant 2
Application
Database
Hardware
Tenant 3
Application
Database
Hardware
Multi Tenancy
Multitenant web applications
Tenant 2Tenant 1
Application
Database
Hardware
Tenant 3
What should be customizable?
Multitenant web applications
What should be customizable?
Tenant 2Tenant 1
Application
Database
Hardware
Tenant 3
Multitenant web applications
What should be customizable?
Tenant 2Tenant 1
Application
Database
Hardware
Tenant 3
Multitenant web applications
How to skin an application?
Multitenant web applications
How to skin an application?
Multitenant web applications
Remember:It`s a web application!
How to skin an application?
Multitenant web applications
HTML
How to skin an application?
Multitenant web applications
HTML + CSS
Multitenant web applications
Multitenant web applications
Multitenant web applications
How to customize?
Multitenant web applications
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0Strict//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>
How to customize?
Multitenant web applications
<!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>
How to customize?
Multitenant web applications
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0Strict//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>
Feature driven CSS
Multitenant web applications
Wait, there`s more...
Feature driven CSS
Multitenant web applications
display: none
Multitenant web applications
This is not an security advice!
Multitenant web applications
Next level...
Menubar generation
Multitenant web applications
<?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); }}
Menubar generation
Multitenant web applications
<?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);}
}}
Menubar generation
Multitenant web applications
Modularize!
Menubar generation
Multitenant web applications
Module 2Module 1
Application core
Module 3
register at start up
Menubar generation
Multitenant web applications
Module 2Module 1
Application core
Module 3
register at start up
Menubar generation
Multitenant web applications
Module 2Module 1
Application core
Module 3
register at start up
Optimize workflows
Multitenant web applications
Optimize workflows
Multitenant web applications
<?php
if('CC' == $paymentType){ // handle credit card payment}else if('COD' == $paymentType){ // handle cash on delivery payment}
Optimize workflows
Multitenant web applications
<?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!}
Optimize workflows
Multitenant web applications
Decouple functionality!
Optimize workflows
Multitenant web applications
<?php
$paymentType = 'CC'; // set via request$payment = PaymentFactory::create($paymentType);
$payment->execute($order);
Optimize workflows
Multitenant web applications
<?php
$paymentType = 'CC'; // set via request$payment = PaymentFactory::create($paymentType, $tenant);
$payment->execute($order);
Optimize workflows
Multitenant web applications
How to add custom logic?
Custom logic - Subclassing?
Multitenant web applications
AbstractPayment
CCPayment
CCPaymentTenant 1
CCPaymentTenant 2
Custom logic
Multitenant web applications
Any alternatives?
Custom logic
Multitenant web applications
Let`s add hooks...
Custom logic - Hooks
Multitenant web applications
<?php
$paymentType = 'CC'; // set via request$payment = PaymentFactory::create($paymentType, $tenant);
$payment->execute($order);
if($this->paymentPostProcessor instanceofIPaymentPostProcessor) { $this->paymentPostProcessor->run($payment, $tenant, $order);}
Custom logic
Multitenant web applications
How to set the dependencies?
Custom logic
Multitenant web applications
Dependency Injection!
Custom logic – Dependency Injection
Multitenant web applications
<?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="Service.Order" class="MyApp\Service\Order.php"></bean>
<bean id="Tenant1.Order" class="MyApp\Service\Order.php"><property name="paymentPostProcessor"
ref="Tentant1.Payment.SendOrderMail" /></bean>
</beans>
Custom logic – Dependency Injection
Multitenant web applications
<?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="Tenant2.Order" class="MyApp\Service\Order.php"><property name="paymentPostProcessor"
ref="Tentant1.Payment.PushToERP" /></bean>
</beans>
Custom logic
Multitenant web applications
Any further improvements?
Custom logic
Multitenant web applications
<?php
$paymentType = 'CC'; // set via request$payment = PaymentFactory::create($paymentType, $tenant);
$payment->execute($order);
if($this->paymentPostProcessor instanceofIPaymentPostProcessor) { $this->paymentPostProcessor->run($payment, $tenant, $order);}
Custom logic
Multitenant web applications
<?php
$paymentType = 'CC'; // set via request$payment = PaymentFactory::create($paymentType, $tenant);
$payment->execute($order);
if($this->paymentPostProcessor instanceofIPaymentPostProcessor) { $this->paymentPostProcessor->run($payment, $tenant, $order);}
Custom logic
Multitenant web applications
Aspect-oriented programming
Custom logic – Aspects for the masses!
Multitenant web applications
/** * @aspect */class CustomPaymentProcessingAspect {
/** * @around MyApp\Service\Order->processPayment */public function customFilter(JoinPointInterface $jP) {
$result = $jP->getAdviceChain()->proceed($jP);
// @TODO: implement post-processing logic
return $result;}
}
Custom logic - Result
Multitenant web applications
<?php
$paymentType = 'CC'; // set via request$payment = PaymentFactory::create($paymentType, $tenant);
$payment->execute($order);
Multitenant web applications
Next level...
Database – Where to store the data?
Multitenant web applications
Database – Where to store the data?
Multitenant web applications
We need to store data for a tenant!
Database – Where to store the data?
Multitenant web applications
Database per Tenant?
Database – Where to store the data?
Multitenant web applications
Database per Tenant?
Schema per Tenant?
Database – Where to store the data?
Multitenant web applications
Database per Tenant?
Schema per Tenant?
Tenant Id per Row?
Database – How to access the data?
Multitenant web applications
ORM dynamic statements
vs.
Multitenant web applications
Generalize you should!
No single solution!
Multitenant web applications
Multitenant web applications
Softwaresystemfamily
A factory for mass production!
Multitenant web applications
Multi Tenancy – Single Instance
Tenant 2Tenant 1
Application
Database
Hardware
Tenant 3
Multitenant web applications
Multi Tenancy – Multi Instance
Tenant 2Tenant 1
Application
Database
Hardware
Tenant 3
Multitenant web applications
Multi Tenancy – Multi Instance
Multitenant web applications
Generative Programming
Generative Programming
Multitenant web applications
GeneratorGenerator
Generative Programming
Multitenant web applications
Configuration(DSL)
Configuration(DSL)
GeneratorGenerator
Generative Programming
Multitenant web applications
Configuration(DSL)
Configuration(DSL)
Implementation-components
Implementation-components GeneratorGenerator
Generative Programming
Multitenant web applications
Configuration(DSL)
Configuration(DSL)
Implementation-components
Implementation-components GeneratorGenerator
ProductProduct
1..n
Generative Programming
Multitenant web applications
Configuration(DSL)
Configuration(DSL)
Implementation-components
Implementation-components GeneratorGenerator
Tenant 1Tenant 1
Generative Programming
Multitenant web applications
Configuration(DSL)
Configuration(DSL)
Implementation-components
Implementation-components GeneratorGenerator
Tenant 1Tenant 1
Tenant 2Tenant 2
Generative Programming
Multitenant web applications
Configuration(DSL)
Configuration(DSL)
Implementation-components
Implementation-components
Tenant 3Tenant 3
GeneratorGeneratorTenant 1Tenant 1
Tenant 2Tenant 2
Generative Programming - Goal
Multitenant web applications
Create an optimized application!
Generative Programming - Goal
Multitenant web applications
Create an optimized application for one tenant!
Generative Programming – Bonus points
Multitenant web applications
Generative Programming – Bonus points
Multitenant web applications
Reduce application complexity
Generative Programming – Bonus points
Multitenant web applications
<?php
$paymentType = 'CC'; // set via request$payment = PaymentFactory::create($paymentType, $tenant);
$payment->execute($order);
<!{PostProcessor}!>
Generative Programming – Bonus points
Multitenant web applications
public class PostProcessorFrame extends SimpleFrameController{
public void execute(Frame frame, FeatureConfig config) {if(config.hasFeature("order_send_mail")) { frame.setSlot("PostProcessor", "...");}
if(config.hasFeature("order_push_to_erp")) { frame.setSlot("PostProcessor", "...");}
}}
Generative Programming – Bonus points
Multitenant web applications
Reduce maintenance support
Generative Programming – Bonus points
Multitenant web applications
FeatureImplementation
component
Generative Programming – Bonus points
Multitenant web applications
Feature Tenant
Generative Programming – Bonus points
Multitenant web applications
Feature
Implementationcomponent
Tenant
Generative Programming – The book
Multitenant web applications
http://joind.in/3517
Flickr Creditshttp://www.flickr.com/photos/andresrueda/3452940751/
http://www.flickr.com/photos/andresrueda/3455410635/