#spug - legacy applications

40
Legacy applications Piotr Pasich @

Upload: piotr-pasich

Post on 01-Dec-2014

787 views

Category:

Technology


1 download

DESCRIPTION

Presentation prepared especially for #4 SPUG meeting in Gliwice describes integration an old code, spaghetti code with Symfony2 framework. Two really different engines in one application.

TRANSCRIPT

Page 1: #SPUG - Legacy applications

Legacy applicationsPiotr Pasich @

Page 2: #SPUG - Legacy applications

więc...przychodzi klient do lekarza

ZACZNIJMY OD KLIENTA

Piotr Pasich @

Page 3: #SPUG - Legacy applications

żeby działałona wczoraj

ewentualnie ASAP

CZEGO OCZEKUJE?

Piotr Pasich @

Page 4: #SPUG - Legacy applications

Ile to będzie trwało?

9 miesięcy

PRZEPISZMY TO!

Piotr Pasich @

Page 5: #SPUG - Legacy applications

Piotr Pasich @

Page 6: #SPUG - Legacy applications

Ile to będzie trwało?

2 miesiące

NADPISZMY TO!

Piotr Pasich @

Page 7: #SPUG - Legacy applications

FROM SPAGHETTI TO CODEczyli dziedziczymy aplikację

Page 8: #SPUG - Legacy applications

PREVENTING REGRESSIONSczyli nic nie ruszać

Piotr Pasich @

Page 9: #SPUG - Legacy applications

TESTY FUNKCJONALNOŚCISelenium IDE, behat, testy jednostkowe

Piotr Pasich @

Page 10: #SPUG - Legacy applications

ŚRODOWISKOminimum PHP 5.3.3Sqlite3, JSON, ctypephp app/check.php

date.timezone set in php.iniPhpcs CodeSniffs

tutaj po raz pierwszy korzystamy z testów

Piotr Pasich @

Page 11: #SPUG - Legacy applications

INSTALACJA SYMFONY 2katalog legacy

namespacenamespace Legacy { (...)}

Piotr Pasich @

Page 12: #SPUG - Legacy applications

LegacyBundleapp/console generate:bundleBundle namespace: Xsolve\LegacyBundle

Piotr Pasich @

Page 13: #SPUG - Legacy applications

AUTOLOADER<?php

namespace Xsolve\LegacyBundle;

require_once(__DIR__ . "/../../../legacy/index.php"); //disabled execute::runuse Legacy;use Symfony\Component\HttpKernel\Bundle\Bundle;use Symfony\Component\DependencyInjection\ContainerBuilder;

class XsolveLegacyBundle extends Bundle{ public function build(ContainerBuilder $container) { spl_autoload_register(array('Kohana', 'auto_load')); } }

Piotr Pasich @

Page 14: #SPUG - Legacy applications

MainActionclass LegacyController extends Controller{ /** * @Route("/", name="main_page") * @Route("/{filename}.html", name="proxy_html", requirements={"filename" = ".+"}) * @Route("/{filename}", name="proxy", requirements={"filename" = ".+"}) */ public function indexAction($filename='index') { $_SERVER['SCRIPT_URL'] = $filename.'.html'; $_SERVER['REQUEST_URI'] = $filename.'.html'; ob_start();// include_once ('../legacy/index.php'); \Event::run('system.routing'); \Benchmark::stop(SYSTEM_BENCHMARK.'_system_initialization'); \Event::run('system.execute'); $response = new Response(ob_get_clean()); return $response; }}

Piotr Pasich @

Page 15: #SPUG - Legacy applications

KOHANA?system/core/Bootstrap.php

//Event::run('system.routing'); //Benchmark::stop(SYSTEM_BENCHMARK.'_system_initialization');//Event::run('system.shutdown');

DIE ( ); //!Piotr Pasich @

Page 16: #SPUG - Legacy applications

LAYOUTesi

VarnishGuzzle Client

Crawler

Piotr Pasich @

Page 17: #SPUG - Legacy applications

ESI + VARNISHhttp://todsul.com/symfony2-esi-varnish

framework: { esi: true }

Piotr Pasich @

Page 18: #SPUG - Legacy applications

ESI CONTROLLER/*** @Route(name="esi_center_column")*/public function getCenterColumnAction(Request $request){ $url = $request->get('url'); //almost like proxy.php $html = $this->get('xsolve.legacy.client')->requestElement($url, '.span-center');

return $this->get('xsolve.response.cache')->getResponseWithCache($html, 10);}

Piotr Pasich @

Page 19: #SPUG - Legacy applications

ESI SERVICEclass LegacyClient{ (...) public function requestElement($url, $element) { $html = $this->request($url); return $this->filter($html, $element); }

(...)

Piotr Pasich @

Page 20: #SPUG - Legacy applications

ESI SERVICE /** * @return \Symfony\Component\DomCrawler\Crawler */ public function request($url) { if (!isset($this->response[$url])) { $client = $this->getClient();

$request = $client->get($url); $request->setHeader('Cookie', null);

$this->response[$url] = $request->send(); }

return $this->response[$url]->getBody(); }

Piotr Pasich @

Page 21: #SPUG - Legacy applications

ESI SERVICE public function filter($html, $element) { $crawler = new Crawler(); $crawler->addHtmlContent($html); $crawler = $crawler->filter($element); $html = '';

foreach ($crawler as $domElement) { $html.= $domElement->ownerDocument->saveHTML($domElement); }

return $html; }

Piotr Pasich @

Page 22: #SPUG - Legacy applications

REVERSE PROXY CACHE// app/AppCache.phprequire_once __DIR__.'/AppKernel.php';

use Symfony\Bundle\FrameworkBundle\HttpCache\HttpCache;

class AppCache extends HttpCache{ protected function getOptions() { return array( 'debug' => false, 'default_ttl' => 0, 'private_headers' => array('Authorization', 'Cookie'), 'allow_reload' => true, 'allow_revalidate' => false, 'stale_while_revalidate' => 2, 'stale_if_error' => 60, ); }}

Piotr Pasich @

Page 23: #SPUG - Legacy applications

REVERSE PROXY CACHE<?php

// web/app.phprequire_once __DIR__.'/../app/bootstrap.php.cache';require_once __DIR__.'/../app/AppKernel.php';require_once __DIR__.'/../app/AppCache.php';

use Symfony\Component\HttpFoundation\Request;

$kernel = new AppKernel('prod', false);$kernel->loadClassCache();// wrap the default AppKernel with the AppCache one$kernel = new AppCache($kernel);$request = Request::createFromGlobals();$response = $kernel->handle($request);$response->send();$kernel->terminate($request, $response);

Piotr Pasich @

Page 24: #SPUG - Legacy applications

REVERSE PROXY CACHEclass ResponseCache { public function getResponseWithCache($html, $cacheTime=1) { $response = new Response($html); $response->setMaxAge($cacheTime); $response->setSharedMaxAge($cacheTime); $date = new \DateTime(); $date->modify("+$cacheTime seconds"); $response->setExpires($date);

return $response; } }

Piotr Pasich @

Page 25: #SPUG - Legacy applications

HOW TO USE IT?<!DOCTYPE html><html> <esi:include src="{{ path('esi_head') }}" /> <body> <div class="container with-background"> <esi:include src="{{ path('esi_left_column') }}" /> <div class="span-center"> {% block content %} {% endblock %} </div> <esi:include src="{{ path('esi_right_column') }}" /> <esi:include src="{{ path('esi_footer') }}" /> </div> </body></html>

Piotr Pasich @

Page 26: #SPUG - Legacy applications

RENDER{% render url('latest_news', { 'max': 5 }) with {}, {'standalone': true} %}

Piotr Pasich @

Page 27: #SPUG - Legacy applications

SESSIONGdzie jest problem?

_s2_(...)

Piotr Pasich @

Page 28: #SPUG - Legacy applications

SESSIONclass RequestListener { public function onKernelRequest(GetResponseEvent $event) { $bags = array( 'total_hits', '_kf_flash_', 'user_agent', 'last_activity', 'search.criteria', 'category.name', 'auth_user' ); foreach ($bags as $namespace) { $bag = new AttributeBag($namespace, '.'); $bag->setName($namespace); $this->session->registerBag($bag); } }}

Piotr Pasich @

Page 29: #SPUG - Legacy applications

REQUEST LISTENER<?xml version="1.0" ?>

<container xmlns="http://symfony.com/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> <services> <service id="xsolve.legacy.listener.request" class="Xsolve\LegacyBundle\RequestListener"> <tag name="kernel.event_listener" event="kernel.request" method="onKernelRequest"/> <argument type="service" id="session" /> </service> </services>

</container>

Piotr Pasich @

Page 30: #SPUG - Legacy applications

NIE DZIAŁA!DLACZEGO?

Piotr Pasich @

Page 31: #SPUG - Legacy applications

BO KOHANA!class Session_Core { // (...) public function create($vars = NULL) { $this->destroy(); // (...) }}

Piotr Pasich @

Page 32: #SPUG - Legacy applications

TERAZ DZIAŁAclass Session_Core { // (...) public function create($vars = NULL) { //$this->destroy(); // (...) }}

Piotr Pasich @

Page 33: #SPUG - Legacy applications

TERAZ NIE DZIAŁA

Piotr Pasich @

Page 34: #SPUG - Legacy applications

TERAZ DZIAŁAclass Session_Core { // (...) public function create($vars = NULL) { // Destroy any current sessions self::$createCall = self::$createCall+1;

if (self::$createCall > 10){ $_SESSION = array(); } // this->destroy(); // (...) }}

Piotr Pasich @

Page 35: #SPUG - Legacy applications

BAZA DANYCHponad 100 tabel = 100 encjibrak odpowiednich relacji

brak pełnej zgodności z wymogami Doctrine 2

Piotr Pasich @

Page 36: #SPUG - Legacy applications

BAZA DANYCHapp/console doctrine:mapping:import XsolveLegacyBundle anotation

Piotr Pasich @

Page 37: #SPUG - Legacy applications

KONFLIKTY I BŁĘDYnaprawiamy ręcznie :(

Piotr Pasich @

Page 38: #SPUG - Legacy applications

PRZEPISUJEMY/*** @Route("/{categoryName}.html")*/public function indexAction($categoryName){ $criterias = array( 'category' => $categoryName );

$offers = $this->get('legacy.offers')->getRandomOffers($criterias);

$view = $this->renderView('XsolveOfferBundle:Default:index.html.twig', array( 'offers' => $offers ));

return $this->get('legacy.response.cache')->getResponseWithCache($view, 2);}

Piotr Pasich @

Page 39: #SPUG - Legacy applications

PRZEPISUJEMY{% extends 'XsolveLegacyBundle:Legacy:layout.html.twig' %}{% block content %}<div class="boxer_main anons_set"> {% for offer in offers %} <div class="anons"> <a href="{{ path('legacy_offers_view' , {'id': offer.id, 'city': offer.city.name|makeUri, 'district': offer.district.name|makeUri, 'slug': offer.name|makeUri}) }}" target="_blank"> <img src="{{ STATIC_URL }}thumbs/gallery/{{ offer.galleryId }}/{{ offer.getRandomPhotoName() }}.128x128" alt="" {#popup_text offer=$offer criteria=$criteria#} /></a><br /> {% if offer.isRealphoto %} <a style="display : inline-block;" class="sprite sprite-ptaszek" href="{{ path('legacy_offers_view' , {'id': offer.id, 'city': offer.city.name|makeUri, 'district': offer.district.name|makeUri, 'slug': offer.name|makeUri}) }}" > </a> {% endif %} <a title="{{ offer.name }}" href="{{ path('legacy_offers_view' , {'id': offer.id, 'city': offer.city.name|makeUri, 'district': offer.district.name|makeUri, 'slug': offer.name|makeUri}) }}" target="_blank"> {{ offer.name }} </a> </div> {% endfor %} <div class="clear"></div></div>{% endblock %}

Piotr Pasich @

Page 40: #SPUG - Legacy applications

I TO DZIAŁAPiotr Pasich @

[email protected]