Upgrade to Pro — share decks privately, control downloads, hide ads and more …

From Legacy to Symfony @ SymfonyLive London 2017

From Legacy to Symfony @ SymfonyLive London 2017

How can one use Symfony 4.0 and PHP 7.2 while working with a legacy application? Starting new projects on latest technology is a no-brainer but how often are you in this position? Most of the time it feels like you're stuck with what you have.

In this talk I'll share my experience migrating a legacy monolith from 2007 (powering a high traffic social network) and an API-centric web application (running an e-commerce marketplace) to Symfony.

Although the talk will be largely technical I'll also share some insights on ROI, non-technical benefits and pitching the idea to your boss.

Sebastian Grodzicki

September 22, 2017
Tweet

More Decks by Sebastian Grodzicki

Other Decks in Technology

Transcript

  1. – Sebastian Grodzicki How can one use Symfony 4.0 and

    PHP 7.2
 while working with a legacy application?
  2. Sebastian Grodzicki • CTO at SHOWROOM • former dev &

    CTO at GoldenLine • SensioLabs Certified
 Symfony Developer (Expert) • PHP developer for 15+ years
  3. • business social network founded in 2005 • in-house framework

    (“Xplod”) • LAMP stack • monolith
  4. – Joel Spolsky, CEO of Stack Overflow The single worst

    strategic mistake that any software company can make:
 rewrite the code from scratch.
  5. Routing self::$map = [ [ 'uri' => '^/oauth/authorize/?(.+)?$', 'action' =>

    'oauth/authorize', ], [ 'uri' => '^/m$', 'action' => 'mobile/touch', ], // 746 more like this ];
  6. Routing public function convert(array $rule) { $route = new Route('/{uri}');

    $route->setRequirement('uri', $this->getRequirement($rule['uri'])); return $route; }
  7. Routing private function addRoute( RouteCollection $collection, array $rule, $controller =

    'legacy.web_dispatching_controller:dispatchAction' ) { $name = sprintf( '__legacy_route_%s_%s_%s', (isset($rule['requireSsl']) ? strtolower($rule['requireSsl']) : 1), (isset($rule['method']) ? strtolower($rule['method']) : ''), md5($rule['uri']) ); $route = $this->converter->convert($rule); $route->setDefault('_controller', $controller); $collection->add($name, $route); }
  8. @LegacyIfRoleNot class AutocompleterController extends Controller { const DEFAULT_LIMIT = 15;

    /** * @LegacyIfRoleNot("ROLE_SYMFONY") * * @param Request $request * @throws AccessDeniedException * @return array */ public function getAction(Request $request) { $this->denyAccessUnlessGranted('ROLE_USER'); $query = $request->query->get('query'); $limit = $request->query->get('limit') ?: self::DEFAULT_LIMIT;
  9. @LegacyIfOldBrowser class AuthenticatedController extends Controller { /** * @LegacyIfRoleNot({"IS_ANONYMOUS","ROLE_SYMFONY"}) *

    @LegacyIfOldBrowser */ public function indexAction(Request $request) { $this->denyAccessUnlessGranted('IS_AUTHENTICATED_ANONYMOUSLY'); /** @var $user User */ $user = $this->getUser(); if (!$user) { return $this->forward('HomepageBundle:Anonymous:index'); }
  10. GoldenLine • developer on-boarding took almost 6 months • no

    documentation • no tests • complexity
  11. • online fashion marketplace founded in 2012 • built on

    Slim micro framework & Phalcon • API-centric
  12. • locked on Phalcon 2 & PHP 5.6 • no

    documentation • no tests • frustration
  13. • API v2 based on Symfony 3 • store front

    v2 (Symfony 3) • SHOWROOM SDK for PHP 2016
  14. PSQL 5432 PHP 5.6 9056 NGINX
 80/443 Varnish 6081 NGINX

    8080 • SSL Termination • Access logs • Redirect HTTP to HTTPS • HTTP Cache • Load balancer • Edge Side Includes (ESI) • PHP-FPM via FastCGI • Virtual Hosts • Access logs • PHP-FPM • PHP 5.6 Elasticsearch
 9200 RabbitMQ
 5672 Redis 6379
  15. PSQL 5432 PHP 5.6 9056 Varnish 6081 NGINX 8080 •

    SSL Termination • Access logs • Redirect HTTP to HTTPS • HTTP Cache • Load balancer • Edge Side Includes (ESI) • PHP-FPM via FastCGI • Virtual Hosts • Access logs • PHP-FPM • PHP 5.6 • PHP 7.1 Elasticsearch
 9200 RabbitMQ
 5672 Redis 6379 PHP 7.1 9071 NGINX 8081 NGINX
 80/443
  16. Varnish backend app1a { .host = "10.0.0.1"; .port = "8080";

    } backend app1b { .host = "10.0.0.2"; .port = "8080"; } backend app1c { .host = "10.0.0.3"; .port = "8080"; } backend app2a { .host = "10.0.0.1"; .port = "8081"; } backend app2b { .host = "10.0.0.2"; .port = "8081"; } backend app2c { .host = "10.0.0.3"; .port = “8081"; }
  17. Varnish sub vcl_init { new v1 = directors.round_robin(); v1.add_backend(app1a); v1.add_backend(app1b);

    v1.add_backend(app1c); new v2 = directors.round_robin(); v2.add_backend(app2a); v2.add_backend(app2b); v2.add_backend(app2c); }
  18. Nginx server { listen 8080; server_name api.shwrm.net; root /home/api_v1/public; location

    / { try_files $uri /index.php$is_args$args; } location ~ ^/index\.php(/|$) { fastcgi_pass 127.0.0.1:9056; include fastcgi_params; internal; } }
  19. Nginx server { listen 8081; server_name api.shwrm.net; root /home/api_v2/web; location

    / { try_files $uri /app.php$is_args$args; } location ~ ^/app\.php(/|$) { fastcgi_pass 127.0.0.1:9071; include fastcgi_params; internal; } }
  20. Varnish sub vcl_recv { if (req.http.Accept == "application/vnd.showroom.v2+json") { set

    req.backend_hint = v2.backend(); } else { set req.backend_hint = v1.backend(); } }
  21. sub vcl_recv { if ( req.url ~ "^/_(wdt|profiler|error|docs)/" || req.url

    ~ "^/assets/" || req.url ~ "^/orders/[0-9]+/refund" ) { set req.backend_hint = v2.backend(); } else { set req.backend_hint = v1.backend(); } } Varnish
  22. PSQL 5432 Varnish 6081 NGINX 8080 Elasticsearch
 9200 RabbitMQ
 5672

    Redis 6379 PHP 7.1 9071 NGINX 8080 PHP 5.6 9056 NGINX
 80/443
  23. ESI

  24. • locked on Phalcon 2 & PHP 5.6 • no

    documentation • no tests • frustration