1 - Development
2 - Delivery
3 - Deplyment
https://twitter.com/BERTILLONClment
https://github.com/skigun
I want to do some Symfony 6 already
- Fuel
- Laravel
- CakePHP
- Zend1 or 2
- Home made framwork
- Slim
- symfony1
- Symfony2
Ecommerce
Ecommerce
Stock
Order
Before
After
... and 867 other php files
# We assume our repository is inside an ecommerce directory
# We move everything in a temporary directory
$ mkdir tmp_legacy && mv ecommerce/* tmp_legacy
# From the existing repository create a new Symfony
$ symfony new ecommerce && mkdir ecommerce/legacy
# Move the whole existing legacy in a legacy folder
$ mv tmp_legacy/* ecommerce/legacy
Symfony 6
Legacy
Symfony 6
Legacy
Symfony 6
Legacy
Router
HTTP Request
Symfony 6
Legacy
Router
HTTP Request
Controller A
Controller B
Controller C
Symfony 6
Legacy
Router
HTTP Request
Controller A
Controller B
Controller C
NotFoundException
class RouterListener
{
public function onKernelRequest(RequestEvent $event)
{
try {
$this->routerListener->onKernelRequest($event);
} catch (NotFoundHttpException $e) {
$response = $this->legacyKernel->handle($event->getRequest());
if ($response->getStatusCode() !== 404) {
$event->setResponse($response);
return $event;
}
throw $e;
}
}
}
class LegacyKernel implements HttpKernelInterface
{
public function handle(Request $request): Response
{
return new Response('some content');
}
}
class LegacyKernel implements HttpKernelInterface
{
public function handle(Request $request): Response
{
ob_start();
require __DIR__.'/legacy/some_legacy_file.php';
$response = ob_get_clean();
return new Response($response);
}
}
Symfony 6
Legacy
Symfony 6
Legacy
class LegacyKernel implements HttpKernelInterface
{
public function __construct(
private ContainerInterface $container
) {}
public function handle(Request $request): Response
{
ob_start();
// find a way to inject the service container
// in the legacy application
require __DIR__.'/legacy/some_legacy_file.php';
$response = ob_get_clean();
return new Response($response);
}
}
class LegacyKernel implements HttpKernelInterface
{
public function handle(Request $request): Response
{
$container = $this->getContainer();
ob_start();
require __DIR__.'/legacy/some_legacy_file.php';
// find a way to inject the container in the legacy application
$response = ob_get_clean();
return new Response($response);
}
}
class LegacyKernel implements HttpKernelInterface
{
public function __construct(
private ContainerInterface $container
) {}
public function handle(Request $request): Response
{
ob_start();
$symfonyContainer = $this->container;
global $symfonyContainer;
require __DIR__.'/legacy/some_legacy_file.php';
$response = ob_get_clean();
return new Response($response);
}
}
class LegacyKernel implements HttpKernelInterface
{
public function handle(Request $request): Response
{
$container = $this->getContainer();
ob_start();
global $container;
require __DIR__.'/legacy/some_legacy_file.php';
$response = ob_get_clean();
return new Response($response);
}
}
<?php
// ./legacy/some_legacy_file.php
include('inclusions/config/config.inc.php');
include('inclusions/fonctions/connexion.inc.php');
include('inclusions/fonctions/fonction_other.inc.php');
include('inclusions/fonctions/formule.inc.php');
if(isset($_SESSION['hall'])) {
//if($_SESSION['hall']->check_hall())
$_SESSION['hall']->register_hall();
$notification = new SmsNotification('An SMS from the legacy but with Symfony code, awesome !');
$symfonyBus = $symfonyContainer->get('messenger')->dispatch(notification);
}
unset($_SESION['hall']);
if(isset($_SESSION['hall_form']))$script_return=$_SESSION['hall_form'].".php";
else $script_return="index2.php";
echo "<script language='javascript'>";
echo "window.location.href='$script_return';";
echo "</script>";
Use the profiler even in legacy
Backward resilient
Better decommissioning
Lesser PullRequest
Better Code Review
Implicit CI
Better productivity
Avoid switching repo
Better collaboration between Teams
We can fix bugs in all projects
Less Managment
Everything is centralized
Dependency managment
Code more reusable
Access Control
Better Continus Integration
Visibility
Cross Team Contribution
Single source of truth
Consistency
Shared Timeline
Atomic commits
Unified CI/CD
Unified build process
Unified deploy process
Refactoring easier
Sharing coding standard
Synchronized release
Sharing dependencies
Version41
Application A
{
"name": "Iphone 27",
"price": 2999.00,
"colour": "red"
}
Application B
Version42
Application A
{
"name": "Iphone 27",
"price": 2999.00,
"colour": "#002222"
}
Application B
$ cd ecommerce
$ symfony new Product --no-git
$ symfony new Order --no-git
$ symfony new Stock --no-git
$ git add -A
$ git commit -m "Setup MonoRepo"
Mono Repository
Mono Repository
ecommerce
product
sotck
order
Mono Repository
ecommerce
product
sotck
order
In order to protect and maintain our application
/ecommerce @global-review
/product @product-team
/stock @product-sotck
/stock @product-order @skigun
/deploy @skigun
paths:
- ./ecommerce/src
- ./stock/src
- ./order/src
layers:
- name: Ecommerce
collectors:
- type: className
regex: .*App\\Ecommerce\\.*
- name: Stock
collectors:
- type: className
regex: .*App\\Stock\\.*
- name: Order
collectors:
- type: className
regex: .*App\\Order\\.*
layers:
- name: Ecommerce
collectors:
- type: className
regex: .*App\\Ecommerce\\.*
- name: Stock
collectors:
- type: className
regex: .*App\\Stock\\.*
- name: PaymentBundle
collectors:
- type: className
regex: .*App\\PaymentBundle\\.*
ruleset:
Ecommerce:
- PaymentBundle
Stock:
- PaymentBundle
# config/packages/dev/web_profiler.yaml
framework:
profiler:
only_exceptions: false
dsn: 'file:/shared_profiler_directory/var/profiler'
# config/packages/dev/web_profiler.yaml
framework:
profiler:
only_exceptions: false
dsn: 'file:/shared_profiler_directory/var/profiler'
Feature: Distributed Profiling
https://twitter.com/BERTILLONClment
https://github.com/skigun
Special thanks to Reinis and Salah <3