More Related Content Similar to How to build customizable multitenant web applications - IPC11 Spring Edition Similar to How to build customizable multitenant web applications - IPC11 Spring Edition (20) More from Stephan Hochdörfer More from Stephan Hochdörfer (20) How to build customizable multitenant web applications - IPC11 Spring Edition2. Multitenant web applications
About me
Stephan Hochdörfer, bitExpert AG
Department Manager Research Labs
enjoying PHP since 1999
S.Hochdoerfer@bitExpert.de
@shochdoerfer
10. Multitenant web applications
Single Tenancy
Tenant 1 Tenant 2 Tenant 3
Application Application Application
Database Database Database
Hardware Hardware Hardware
22. Multitenant web applications
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>
23. Multitenant web applications
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>
24. Multitenant web applications
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>
29. Multitenant web applications
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);
}
}
30. Multitenant web applications
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);
}
}
}
36. Multitenant web applications
Optimize workflows
<?php
if('CC' == $paymentType)
{
// handle credit card payment
}
else if('COD' == $paymentType)
{
// handle cash on delivery payment
}
37. Multitenant web applications
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!
}
39. Multitenant web applications
Optimize workflows
<?php
$paymentType = 'CC'; // set via request
$payment = PaymentFactory::create($paymentType);
$payment->execute($order);
40. Multitenant web applications
Optimize workflows
<?php
$paymentType = 'CC'; // set via request
$payment = PaymentFactory::create($paymentType, $tenant);
$payment->execute($order);
45. Multitenant web applications
Custom logic - Hooks
<?php
$paymentType = 'CC'; // set via request
$payment = PaymentFactory::create($paymentType, $tenant);
$payment->execute($order);
if($this->paymentPostProcessor instanceof
IPaymentPostProcessor) {
$this->paymentPostProcessor->run($payment, $tenant, $order);
}
48. Multitenant web applications
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="Service.Order" class="MyAppServiceOrder.php">
</bean>
<bean id="Tenant1.Order" class="MyAppServiceOrder.php">
<property name="paymentPostProcessor"
ref="Tentant1.Payment.SendOrderMail" />
</bean>
</beans>
49. Multitenant web applications
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="Tenant2.Order" class="MyAppServiceOrder.php">
<property name="paymentPostProcessor"
ref="Tentant1.Payment.PushToERP" />
</bean>
</beans>
51. Multitenant web applications
Custom logic
<?php
$paymentType = 'CC'; // set via request
$payment = PaymentFactory::create($paymentType, $tenant);
$payment->execute($order);
if($this->paymentPostProcessor instanceof
IPaymentPostProcessor) {
$this->paymentPostProcessor->run($payment, $tenant, $order);
}
52. Multitenant web applications
Custom logic
<?php
$paymentType = 'CC'; // set via request
$payment = PaymentFactory::create($paymentType, $tenant);
$payment->execute($order);
if($this->paymentPostProcessor instanceof
IPaymentPostProcessor) {
$this->paymentPostProcessor->run($payment, $tenant, $order);
}
54. Multitenant web applications
Custom logic – Aspects for the masses!
/**
* @aspect
*/
class CustomPaymentProcessingAspect {
/**
* @around MyAppServiceOrder->processPayment
*/
public function customFilter(JoinPointInterface $jP) {
$result = $jP->getAdviceChain()->proceed($jP);
// @TODO: implement post-processing logic
return $result;
}
}
55. Multitenant web applications
Custom logic - Result
<?php
$paymentType = 'CC'; // set via request
$payment = PaymentFactory::create($paymentType, $tenant);
$payment->execute($order);
72. Multitenant web applications
Generative Programming
Configuration
Configuration
(DSL)
(DSL)
Implementation-
Implementation-
components
Generator
Generator
components
73. Multitenant web applications
Generative Programming
Configuration
Configuration
(DSL)
(DSL)
1..n
Implementation-
Implementation-
components
Generator
Generator Product
components Product
74. Multitenant web applications
Generative Programming
Configuration
Configuration
(DSL)
(DSL)
Implementation-
Implementation-
components
Generator
Generator Tenant 11
components Tenant
75. Multitenant web applications
Generative Programming
Configuration
Configuration
(DSL)
(DSL)
Tenant 22
Tenant
Implementation-
Implementation-
components
Generator
Generator Tenant 11
components Tenant
76. Multitenant web applications
Generative Programming
Tenant 33
Tenant
Configuration
Configuration
(DSL)
(DSL)
Tenant 22
Tenant
Implementation-
Implementation-
components
Generator
Generator Tenant 11
components Tenant
81. Multitenant web applications
Generative Programming – Bonus points
<?php
$paymentType = 'CC'; // set via request
$payment = PaymentFactory::create($paymentType, $tenant);
$payment->execute($order);
<!{PostProcessor}!>
82. Multitenant web applications
Generative Programming – Bonus points
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", "...");
}
}
}