• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
#SPUG - Legacy applications
 

#SPUG - Legacy applications

on

  • 693 views

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.

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.

Statistics

Views

Total Views
693
Views on SlideShare
692
Embed Views
1

Actions

Likes
0
Downloads
3
Comments
0

1 Embed 1

https://twitter.com 1

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

CC Attribution-NonCommercial LicenseCC Attribution-NonCommercial License

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    #SPUG - Legacy applications #SPUG - Legacy applications Presentation Transcript

    • Legacy applicationsPiotr Pasich @
    • więc...przychodzi klient do lekarzaZACZNIJMY OD KLIENTAPiotr Pasich @
    • żeby działałona wczorajewentualnie ASAPCZEGO OCZEKUJE?Piotr Pasich @
    • Ile to będzie trwało?9 miesięcyPRZEPISZMY TO!Piotr Pasich @
    • Piotr Pasich @
    • Ile to będzie trwało?2 miesiąceNADPISZMY TO!Piotr Pasich @
    • FROM SPAGHETTI TO CODE
    • PREVENTING REGRESSIONSczyli nic nie ruszaćPiotr Pasich @
    • TESTY FUNKCJONALNOŚCISelenium IDE, behat, testy jednostkowePiotr Pasich @
    • ŚRODOWISKOminimum PHP 5.3.3Sqlite3, JSON, ctypephp app/check.phpdate.timezone set in php.iniPhpcs CodeSniffstutaj po raz pierwszy korzystamy z testówPiotr Pasich @
    • INSTALACJA SYMFONY 2katalog legacynamespacenamespace Legacy {(...)}Piotr Pasich @
    • LegacyBundleapp/console generate:bundleBundle namespace: XsolveLegacyBundlePiotr Pasich @
    • AUTOLOADER<?phpnamespace XsolveLegacyBundle;require_once(__DIR__ . "/../../../legacy/index.php"); //disabled execute::runuse Legacy;use SymfonyComponentHttpKernelBundleBundle;use SymfonyComponentDependencyInjectionContainerBuilder;class XsolveLegacyBundle extends Bundle{public function build(ContainerBuilder $container){spl_autoload_register(array(Kohana, auto_load));}}Piotr Pasich @
    • 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 @
    • KOHANA?system/core/Bootstrap.php//Event::run(system.routing);//Benchmark::stop(SYSTEM_BENCHMARK._system_initialization);//Event::run(system.shutdown);DIE ( ); //!Piotr Pasich @
    • LAYOUTesiVarnishGuzzle ClientCrawlerPiotr Pasich @
    • ESI + VARNISHhttp://todsul.com/symfony2-esi-varnishframework: { esi: true }Piotr Pasich @
    • 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 @
    • ESI SERVICEclass LegacyClient{(...)public function requestElement($url, $element){$html = $this->request($url);return $this->filter($html, $element);}(...)Piotr Pasich @
    • ESI SERVICE/*** @return SymfonyComponentDomCrawlerCrawler*/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 @
    • ESI SERVICEpublic 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 @
    • REVERSE PROXY CACHE// app/AppCache.phprequire_once __DIR__./AppKernel.php;use SymfonyBundleFrameworkBundleHttpCacheHttpCache;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 @
    • 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 SymfonyComponentHttpFoundationRequest;$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 @
    • 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 @
    • 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 @
    • RENDER{% render url(latest_news, { max: 5 }) with {}, {standalone: true} %}Piotr Pasich @
    • SESSIONGdzie jest problem?_s2_(...)Piotr Pasich @
    • 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 @
    • 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.><services><service id="xsolve.legacy.listener.request" class="XsolveLegacyBundleRequestListener"><tag name="kernel.event_listener" event="kernel.request" method="onKernelRequest"/><argument type="service" id="session" /></service></services></container>Piotr Pasich @
    • NIE DZIAŁA!DLACZEGO?Piotr Pasich @
    • BO KOHANA!class Session_Core {// (...)public function create($vars = NULL){$this->destroy();// (...)}}Piotr Pasich @
    • TERAZ DZIAŁAclass Session_Core {// (...)public function create($vars = NULL){//$this->destroy();// (...)}}Piotr Pasich @
    • TERAZ NIE DZIAŁAPiotr Pasich @
    • TERAZ DZIAŁAclass Session_Core {// (...)public function create($vars = NULL){// Destroy any current sessionsself::$createCall = self::$createCall+1;if (self::$createCall > 10){$_SESSION = array();}// this->destroy();// (...)}}Piotr Pasich @
    • BAZA DANYCHponad 100 tabel = 100 encjibrak odpowiednich relacjibrak pełnej zgodności z wymogami Doctrine 2Piotr Pasich @
    • BAZA DANYCHapp/console doctrine:mapping:import XsolveLegacyBundle anotationPiotr Pasich @
    • KONFLIKTY I BŁĘDYnaprawiamy ręcznie :(Piotr Pasich @
    • 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 @
    • 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 @
    • I TO DZIAŁAPiotr Pasich @piotr.pasich@xsolve.plwww.xsolve.plwww.xlab.pl