• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
Legacy applications  - 4Developes konferencja, Piotr Pasich
 

Legacy applications - 4Developes konferencja, Piotr Pasich

on

  • 620 views

 

Statistics

Views

Total Views
620
Views on SlideShare
588
Embed Views
32

Actions

Likes
2
Downloads
4
Comments
0

2 Embeds 32

http://lanyrd.com 31
https://twitter.com 1

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

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

    Legacy applications  - 4Developes konferencja, Piotr Pasich Legacy applications - 4Developes konferencja, Piotr Pasich Presentation Transcript

    • LEGACY APPLICATIONSPiotr Pasich
    • Piotr Pasich @FROM SPAGHETTI TO CODEczyli dziedziczymy aplikację
    • DLACZEGO TEGO NIE PRZEPISAĆ?Piotr Pasich @
    • dużo koduduża ilość funkcjonalnościczaspieniądzePiotr Pasich @
    • 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 legacynamespacePiotr Pasich @namespace Legacy {(...)}
    • 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 SERVICE/*** @return GuzzleHttpClient*/public function getClient(){$client = new Client();return $client;}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 @
    • 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 @
    • 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 @
    • 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 @
    • RENDER{% render url(latest_news, { max: 5 }) with {}, {standalone: true} %}Piotr Pasich @
    • ROUTINGnamespace XsolveLegacyBundleService;class LegacyRouter{/** @var array Legacy routes configuration */protected $config;public function __construct(Router $router){include __DIR__./../../../../legacy/application/config/urls.php;$this->config = $config;$this->router = $router;$this->locale = $this->router->getContext()->getParameter(_locale);}// (..)}Piotr Pasich @
    • KONFIGURACJAclass LegacyConfiguration{protected $configuration;public function __construct($configuration){$this->configuration = $configuration;}public function onKernelRequest(GetResponseEvent $event){global $legacyConfig;$legacyConfig = $this->configuration;}}Piotr Pasich @
    • KONFIGURACJAglobal $legacyConfig;$config[default] = $legacyConfig[database][default];$config[import] = $legacyConfig[database][import];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 @
    • SESSIONnamespace XsolveLegacyBundleSession;use SymfonyComponentHttpFoundationSessionAttributeAttributeBagInterface;use SymfonyComponentHttpFoundationSessionSessionBagInterface;use XsolveLegacyBundleSessionScalarBagInterface;/*** This class provides scalar storage of session attributes using* a name spacing character in the key.** @author Piotr Pasich <piotr.pasich@xsolve.pl>*/class ScalarBag implements ScalarBagInterface, SessionBagInterface{// (...)}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.xsd"><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 annotationPiotr 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 @
    • I TO DZIAŁA!Piotr Pasich @
    • DZIĘKUJĘ ZA UWAGĘPiotr Pasichpiotr.pasich@xsolve.plwww.xsolve.pl