SlideShare uma empresa Scribd logo
1 de 40
Baixar para ler offline
Legacy applications
Piotr Pasich @
więc...
przychodzi klient do lekarza
ZACZNIJMY OD KLIENTA
Piotr Pasich @
żeby działało
na wczoraj
ewentualnie ASAP
CZEGO OCZEKUJE?
Piotr Pasich @
Ile to będzie trwało?
9 miesięcy
PRZEPISZMY TO!
Piotr Pasich @
Piotr Pasich @
Ile to będzie trwało?
2 miesiące
NADPISZMY TO!
Piotr Pasich @
FROM SPAGHETTI TO CODE
PREVENTING REGRESSIONS
czyli nic nie ruszać
Piotr Pasich @
TESTY FUNKCJONALNOŚCI
Selenium IDE, behat, testy jednostkowe
Piotr Pasich @
ŚRODOWISKO
minimum PHP 5.3.3
Sqlite3, JSON, ctype
php app/check.php
date.timezone set in php.ini
Phpcs CodeSniffs
tutaj po raz pierwszy korzystamy z testów
Piotr Pasich @
INSTALACJA SYMFONY 2
katalog legacy
namespace
namespace Legacy {
(...)
}
Piotr Pasich @
LegacyBundle
app/console generate:bundle
Bundle namespace: XsolveLegacyBundle
Piotr Pasich @
AUTOLOADER
<?php
namespace XsolveLegacyBundle;
require_once(__DIR__ . "/../../../legacy/index.php"); //disabled execute::run
use Legacy;
use SymfonyComponentHttpKernelBundleBundle;
use SymfonyComponentDependencyInjectionContainerBuilder;
class XsolveLegacyBundle extends Bundle
{
public function build(ContainerBuilder $container)
{
spl_autoload_register(array('Kohana', 'auto_load'));
}
}
Piotr Pasich @
MainAction
class 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 @
LAYOUT
esi
Varnish
Guzzle Client
Crawler
Piotr Pasich @
ESI + VARNISH
http://todsul.com/symfony2-esi-varnish
framework: { 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 SERVICE
class 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
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 @
REVERSE PROXY CACHE
// app/AppCache.php
require_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.php
require_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 CACHE
class 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 @
SESSION
Gdzie jest problem?
_s2_(...)
Piotr Pasich @
SESSION
class 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ŁA
class Session_Core {
// (...)
public function create($vars = NULL)
{
//$this->destroy();
// (...)
}
}
Piotr Pasich @
TERAZ NIE DZIAŁA
Piotr Pasich @
TERAZ DZIAŁA
class 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 @
BAZA DANYCH
ponad 100 tabel = 100 encji
brak odpowiednich relacji
brak pełnej zgodności z wymogami Doctrine 2
Piotr Pasich @
BAZA DANYCH
app/console doctrine:mapping:import XsolveLegacyBundle anotation
Piotr Pasich @
KONFLIKTY I BŁĘDY
naprawiamy 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ŁA
Piotr Pasich @
piotr.pasich@xsolve.pl
www.xsolve.pl
www.xlab.pl

Mais conteúdo relacionado

Mais procurados

Europython 2011 - Playing tasks with Django & Celery
Europython 2011 - Playing tasks with Django & CeleryEuropython 2011 - Playing tasks with Django & Celery
Europython 2011 - Playing tasks with Django & Celery
Mauro Rocco
 
Kansai.pm 10周年記念 Plack/PSGI 入門
Kansai.pm 10周年記念 Plack/PSGI 入門Kansai.pm 10周年記念 Plack/PSGI 入門
Kansai.pm 10周年記念 Plack/PSGI 入門
lestrrat
 

Mais procurados (20)

Memory Manglement in Raku
Memory Manglement in RakuMemory Manglement in Raku
Memory Manglement in Raku
 
Lies, Damn Lies, and Benchmarks
Lies, Damn Lies, and BenchmarksLies, Damn Lies, and Benchmarks
Lies, Damn Lies, and Benchmarks
 
Nubilus Perl
Nubilus PerlNubilus Perl
Nubilus Perl
 
BASH Variables Part 1: Basic Interpolation
BASH Variables Part 1: Basic InterpolationBASH Variables Part 1: Basic Interpolation
BASH Variables Part 1: Basic Interpolation
 
Nigel hamilton-megameet-2013
Nigel hamilton-megameet-2013Nigel hamilton-megameet-2013
Nigel hamilton-megameet-2013
 
Selenium sandwich-3: Being where you aren't.
Selenium sandwich-3: Being where you aren't.Selenium sandwich-3: Being where you aren't.
Selenium sandwich-3: Being where you aren't.
 
Europython 2011 - Playing tasks with Django & Celery
Europython 2011 - Playing tasks with Django & CeleryEuropython 2011 - Playing tasks with Django & Celery
Europython 2011 - Playing tasks with Django & Celery
 
An Introduction to Celery
An Introduction to CeleryAn Introduction to Celery
An Introduction to Celery
 
Puppet: What _not_ to do
Puppet: What _not_ to doPuppet: What _not_ to do
Puppet: What _not_ to do
 
PuppetCamp Ghent - What Not to Do with Puppet
PuppetCamp Ghent - What Not to Do with PuppetPuppetCamp Ghent - What Not to Do with Puppet
PuppetCamp Ghent - What Not to Do with Puppet
 
Django Celery - A distributed task queue
Django Celery - A distributed task queueDjango Celery - A distributed task queue
Django Celery - A distributed task queue
 
Fake My Party
Fake My PartyFake My Party
Fake My Party
 
Getting testy with Perl
Getting testy with PerlGetting testy with Perl
Getting testy with Perl
 
V2 and beyond
V2 and beyondV2 and beyond
V2 and beyond
 
Perl Sucks - and what to do about it
Perl Sucks - and what to do about itPerl Sucks - and what to do about it
Perl Sucks - and what to do about it
 
Great Developers Steal
Great Developers StealGreat Developers Steal
Great Developers Steal
 
Building Cloud Castles - LRUG
Building Cloud Castles - LRUGBuilding Cloud Castles - LRUG
Building Cloud Castles - LRUG
 
Findbin libs
Findbin libsFindbin libs
Findbin libs
 
Perl web app 테스트전략
Perl web app 테스트전략Perl web app 테스트전략
Perl web app 테스트전략
 
Kansai.pm 10周年記念 Plack/PSGI 入門
Kansai.pm 10周年記念 Plack/PSGI 入門Kansai.pm 10周年記念 Plack/PSGI 入門
Kansai.pm 10周年記念 Plack/PSGI 入門
 

Destaque

A2 Media Studies - Music Video Analysis
A2 Media Studies - Music Video AnalysisA2 Media Studies - Music Video Analysis
A2 Media Studies - Music Video Analysis
Pheebs023
 
2008 smid
2008 smid2008 smid
2008 smid
604381
 
васькин мнск13
васькин мнск13васькин мнск13
васькин мнск13
vaskinyy
 
PHPConPl 2013 - Allowed memory size of X bytes exhausted
PHPConPl 2013 - Allowed memory size of X bytes exhaustedPHPConPl 2013 - Allowed memory size of X bytes exhausted
PHPConPl 2013 - Allowed memory size of X bytes exhausted
Piotr Pasich
 
Tracking norm
Tracking normTracking norm
Tracking norm
y_anni
 
ідеї для вечірнього макіяжу
ідеї для вечірнього макіяжуідеї для вечірнього макіяжу
ідеї для вечірнього макіяжу
AnnaBoyko1
 
устюгова катя 145 группа
устюгова катя 145 группаустюгова катя 145 группа
устюгова катя 145 группа
Katya Ustyugova
 
Water customer presentation
Water customer presentationWater customer presentation
Water customer presentation
Suj Kang
 

Destaque (19)

A2 Media Studies - Music Video Analysis
A2 Media Studies - Music Video AnalysisA2 Media Studies - Music Video Analysis
A2 Media Studies - Music Video Analysis
 
2008 smid
2008 smid2008 smid
2008 smid
 
eToro DevOps presentation
eToro DevOps presentationeToro DevOps presentation
eToro DevOps presentation
 
Project management and unveiling risks
Project management and unveiling risksProject management and unveiling risks
Project management and unveiling risks
 
Twitter
TwitterTwitter
Twitter
 
Empowering The Mature Mind - SUMMER 2014 Newsletter
Empowering The Mature Mind - SUMMER 2014 NewsletterEmpowering The Mature Mind - SUMMER 2014 Newsletter
Empowering The Mature Mind - SUMMER 2014 Newsletter
 
васькин мнск13
васькин мнск13васькин мнск13
васькин мнск13
 
Reaching & Connecting with the BOOMER CONSUMER - by EtMM Aaron D. Murphy
Reaching & Connecting with the BOOMER CONSUMER - by EtMM Aaron D. MurphyReaching & Connecting with the BOOMER CONSUMER - by EtMM Aaron D. Murphy
Reaching & Connecting with the BOOMER CONSUMER - by EtMM Aaron D. Murphy
 
PHPConPl 2013 - Allowed memory size of X bytes exhausted
PHPConPl 2013 - Allowed memory size of X bytes exhaustedPHPConPl 2013 - Allowed memory size of X bytes exhausted
PHPConPl 2013 - Allowed memory size of X bytes exhausted
 
Performance
PerformancePerformance
Performance
 
Time management
Time managementTime management
Time management
 
Tracking norm
Tracking normTracking norm
Tracking norm
 
ідеї для вечірнього макіяжу
ідеї для вечірнього макіяжуідеї для вечірнього макіяжу
ідеї для вечірнього макіяжу
 
Tugas kkpi
Tugas kkpiTugas kkpi
Tugas kkpi
 
Task groups
Task groupsTask groups
Task groups
 
Users in casual
Users in casualUsers in casual
Users in casual
 
устюгова катя 145 группа
устюгова катя 145 группаустюгова катя 145 группа
устюгова катя 145 группа
 
Water customer presentation
Water customer presentationWater customer presentation
Water customer presentation
 
PPM (Private Equtiy/Stock Offering)
PPM (Private Equtiy/Stock Offering)PPM (Private Equtiy/Stock Offering)
PPM (Private Equtiy/Stock Offering)
 

Semelhante a #SPUG - Legacy applications

EPHPC Webinar Slides: Unit Testing by Arthur Purnama
EPHPC Webinar Slides: Unit Testing by Arthur PurnamaEPHPC Webinar Slides: Unit Testing by Arthur Purnama
EPHPC Webinar Slides: Unit Testing by Arthur Purnama
Enterprise PHP Center
 
Zendcon 2007 Api Design
Zendcon 2007 Api DesignZendcon 2007 Api Design
Zendcon 2007 Api Design
unodelostrece
 
Remedie: Building a desktop app with HTTP::Engine, SQLite and jQuery
Remedie: Building a desktop app with HTTP::Engine, SQLite and jQueryRemedie: Building a desktop app with HTTP::Engine, SQLite and jQuery
Remedie: Building a desktop app with HTTP::Engine, SQLite and jQuery
Tatsuhiko Miyagawa
 
Quality Assurance for PHP projects - ZendCon 2012
Quality Assurance for PHP projects - ZendCon 2012Quality Assurance for PHP projects - ZendCon 2012
Quality Assurance for PHP projects - ZendCon 2012
Michelangelo van Dam
 

Semelhante a #SPUG - Legacy applications (20)

Advanced PHPUnit Testing
Advanced PHPUnit TestingAdvanced PHPUnit Testing
Advanced PHPUnit Testing
 
Ch ch-changes cake php2
Ch ch-changes cake php2Ch ch-changes cake php2
Ch ch-changes cake php2
 
EPHPC Webinar Slides: Unit Testing by Arthur Purnama
EPHPC Webinar Slides: Unit Testing by Arthur PurnamaEPHPC Webinar Slides: Unit Testing by Arthur Purnama
EPHPC Webinar Slides: Unit Testing by Arthur Purnama
 
Building Testable PHP Applications
Building Testable PHP ApplicationsBuilding Testable PHP Applications
Building Testable PHP Applications
 
Workshop quality assurance for php projects - ZendCon 2013
Workshop quality assurance for php projects - ZendCon 2013Workshop quality assurance for php projects - ZendCon 2013
Workshop quality assurance for php projects - ZendCon 2013
 
Zendcon 2007 Api Design
Zendcon 2007 Api DesignZendcon 2007 Api Design
Zendcon 2007 Api Design
 
Remedie: Building a desktop app with HTTP::Engine, SQLite and jQuery
Remedie: Building a desktop app with HTTP::Engine, SQLite and jQueryRemedie: Building a desktop app with HTTP::Engine, SQLite and jQuery
Remedie: Building a desktop app with HTTP::Engine, SQLite and jQuery
 
Workshop quality assurance for php projects - phpbelfast
Workshop quality assurance for php projects - phpbelfastWorkshop quality assurance for php projects - phpbelfast
Workshop quality assurance for php projects - phpbelfast
 
Bootstrat REST APIs with Laravel 5
Bootstrat REST APIs with Laravel 5Bootstrat REST APIs with Laravel 5
Bootstrat REST APIs with Laravel 5
 
Unittests für Dummies
Unittests für DummiesUnittests für Dummies
Unittests für Dummies
 
REST with Eve and Python
REST with Eve and PythonREST with Eve and Python
REST with Eve and Python
 
WordPress Realtime - WordCamp São Paulo 2015
WordPress Realtime - WordCamp São Paulo 2015WordPress Realtime - WordCamp São Paulo 2015
WordPress Realtime - WordCamp São Paulo 2015
 
Quality Assurance for PHP projects - ZendCon 2012
Quality Assurance for PHP projects - ZendCon 2012Quality Assurance for PHP projects - ZendCon 2012
Quality Assurance for PHP projects - ZendCon 2012
 
Workshop quality assurance for php projects tek12
Workshop quality assurance for php projects tek12Workshop quality assurance for php projects tek12
Workshop quality assurance for php projects tek12
 
Best Practices in Plugin Development (WordCamp Seattle)
Best Practices in Plugin Development (WordCamp Seattle)Best Practices in Plugin Development (WordCamp Seattle)
Best Practices in Plugin Development (WordCamp Seattle)
 
Debugging: Rules And Tools - PHPTek 11 Version
Debugging: Rules And Tools - PHPTek 11 VersionDebugging: Rules And Tools - PHPTek 11 Version
Debugging: Rules And Tools - PHPTek 11 Version
 
Introduction to PHP
Introduction to PHPIntroduction to PHP
Introduction to PHP
 
Fatc
FatcFatc
Fatc
 
Debugging: Rules & Tools
Debugging: Rules & ToolsDebugging: Rules & Tools
Debugging: Rules & Tools
 
Build restful ap is with python and flask
Build restful ap is with python and flaskBuild restful ap is with python and flask
Build restful ap is with python and flask
 

Mais de Piotr Pasich

Simplify your code with annotations - SymfonyCon Warsaw 2013
Simplify your code with annotations - SymfonyCon Warsaw 2013Simplify your code with annotations - SymfonyCon Warsaw 2013
Simplify your code with annotations - SymfonyCon Warsaw 2013
Piotr Pasich
 
SpreadIT - Make your project SOLID!
SpreadIT - Make your project SOLID! SpreadIT - Make your project SOLID!
SpreadIT - Make your project SOLID!
Piotr Pasich
 

Mais de Piotr Pasich (7)

Messaging queues with RabbitMQ
Messaging queues with RabbitMQMessaging queues with RabbitMQ
Messaging queues with RabbitMQ
 
How to write applications prepared for every cataclysm with Event Sourcing an...
How to write applications prepared for every cataclysm with Event Sourcing an...How to write applications prepared for every cataclysm with Event Sourcing an...
How to write applications prepared for every cataclysm with Event Sourcing an...
 
Varnish - Tips & Tricks - 4Developers 2015
Varnish - Tips & Tricks - 4Developers 2015Varnish - Tips & Tricks - 4Developers 2015
Varnish - Tips & Tricks - 4Developers 2015
 
Arduino - SymfonyCon 2014 Lighting Talks
Arduino - SymfonyCon 2014 Lighting TalksArduino - SymfonyCon 2014 Lighting Talks
Arduino - SymfonyCon 2014 Lighting Talks
 
Game of performance - Message Brokers behind the scenes
Game of performance - Message Brokers behind the scenesGame of performance - Message Brokers behind the scenes
Game of performance - Message Brokers behind the scenes
 
Simplify your code with annotations - SymfonyCon Warsaw 2013
Simplify your code with annotations - SymfonyCon Warsaw 2013Simplify your code with annotations - SymfonyCon Warsaw 2013
Simplify your code with annotations - SymfonyCon Warsaw 2013
 
SpreadIT - Make your project SOLID!
SpreadIT - Make your project SOLID! SpreadIT - Make your project SOLID!
SpreadIT - Make your project SOLID!
 

Último

CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Service
giselly40
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
Joaquim Jorge
 

Último (20)

Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path Mount
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Service
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slides
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
Advantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your BusinessAdvantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your Business
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonets
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024
 

#SPUG - Legacy applications

  • 2. więc... przychodzi klient do lekarza ZACZNIJMY OD KLIENTA Piotr Pasich @
  • 3. żeby działało na wczoraj ewentualnie ASAP CZEGO OCZEKUJE? Piotr Pasich @
  • 4. Ile to będzie trwało? 9 miesięcy PRZEPISZMY TO! Piotr Pasich @
  • 6. Ile to będzie trwało? 2 miesiące NADPISZMY TO! Piotr Pasich @
  • 8. PREVENTING REGRESSIONS czyli nic nie ruszać Piotr Pasich @
  • 9. TESTY FUNKCJONALNOŚCI Selenium IDE, behat, testy jednostkowe Piotr Pasich @
  • 10. ŚRODOWISKO minimum PHP 5.3.3 Sqlite3, JSON, ctype php app/check.php date.timezone set in php.ini Phpcs CodeSniffs tutaj po raz pierwszy korzystamy z testów Piotr Pasich @
  • 11. INSTALACJA SYMFONY 2 katalog legacy namespace namespace Legacy { (...) } Piotr Pasich @
  • 13. AUTOLOADER <?php namespace XsolveLegacyBundle; require_once(__DIR__ . "/../../../legacy/index.php"); //disabled execute::run use Legacy; use SymfonyComponentHttpKernelBundleBundle; use SymfonyComponentDependencyInjectionContainerBuilder; class XsolveLegacyBundle extends Bundle { public function build(ContainerBuilder $container) { spl_autoload_register(array('Kohana', 'auto_load')); } } Piotr Pasich @
  • 14. MainAction class 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 @
  • 18. 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 @
  • 19. ESI SERVICE class LegacyClient { (...) public function requestElement($url, $element) { $html = $this->request($url); return $this->filter($html, $element); } (...) Piotr Pasich @
  • 20. 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 @
  • 21. 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 @
  • 22. REVERSE PROXY CACHE // app/AppCache.php require_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 @
  • 23. REVERSE PROXY CACHE <?php // web/app.php require_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 @
  • 24. REVERSE PROXY CACHE class 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 @
  • 25. 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 @
  • 26. RENDER {% render url('latest_news', { 'max': 5 }) with {}, {'standalone': true} %} Piotr Pasich @
  • 28. SESSION class 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 @
  • 29. 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 @
  • 31. BO KOHANA!class Session_Core { // (...) public function create($vars = NULL) { $this->destroy(); // (...) } } Piotr Pasich @
  • 32. TERAZ DZIAŁA class Session_Core { // (...) public function create($vars = NULL) { //$this->destroy(); // (...) } } Piotr Pasich @
  • 34. TERAZ DZIAŁA class 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 @
  • 35. BAZA DANYCH ponad 100 tabel = 100 encji brak odpowiednich relacji brak pełnej zgodności z wymogami Doctrine 2 Piotr Pasich @
  • 36. BAZA DANYCH app/console doctrine:mapping:import XsolveLegacyBundle anotation Piotr Pasich @
  • 37. KONFLIKTY I BŁĘDY naprawiamy ręcznie :( Piotr Pasich @
  • 38. 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 @
  • 39. 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 @
  • 40. I TO DZIAŁA Piotr Pasich @ piotr.pasich@xsolve.pl www.xsolve.pl www.xlab.pl