From * to Symfony2

60
From * to Symfony 2 * Sf1, Zf1, PHP plain, … Manuel “Kea” Baldassarri

Transcript of From * to Symfony2

Page 1: From * to Symfony2

From * to Symfony 2

* Sf1, Zf1, PHP plain, …

Manuel “Kea” Baldassarri

Page 2: From * to Symfony2

If anything can go wrong, it will

Capt. Edward A. Murphy

Page 3: From * to Symfony2

Agenda

• rewrite vs. migration

• code organization

• routing

• database

• authentication aka session

Page 4: From * to Symfony2

Program complexity grows until it exceeds the capability of the programmer who must maintain it.

Murphy's laws

Page 5: From * to Symfony2

Rewrite vs

migration

Page 6: From * to Symfony2

Rewrite (theory)Fe

atur

es

0

30

60

90

120

t0 t1 t2 t3 t4 t5

Old site New site

Page 7: From * to Symfony2

If anything can go wrong, it will

Murphy's laws

Page 8: From * to Symfony2

Rewrite (real)

0

30

60

90

120

t0 t1 t2 t3 t4 t5

Old site New site real

Page 9: From * to Symfony2

RewriteEstimations are wrong, the legacy code is worse than your wildest imagination, the customer wants new features, you have to maintain the current site and develop the new code base, you code fast, port the same feature from the old site to the new one, import db, deploy, switch…

Page 10: From * to Symfony2
Page 11: From * to Symfony2

MigrationFe

atur

es

0

30

60

90

120

t0 t1 t2 t3 t4 t5

Old tech New tech Total

Page 12: From * to Symfony2

Rewrite: practice

Only two steps if you decide to rewrite your paper

Page 13: From * to Symfony2

• Foto con mac e blocco

Page 14: From * to Symfony2

Rewrite

$ rm -Rf project $ symfony new project

Page 15: From * to Symfony2
Page 16: From * to Symfony2

Pre migration

PHP > 5.3

Page 17: From * to Symfony2

Symfony 1.5

LExpress/symfony1

Page 18: From * to Symfony2

PHPCompatibility

$ phpcs --standard=PHPCompatibility \ --runtime-set testVersion 5.6

Page 19: From * to Symfony2

Code structure: as you wish

Page 20: From * to Symfony2

Routing: multiple entry

point

Page 21: From * to Symfony2
Page 22: From * to Symfony2

Catch’em all route/** * @Route("/{filename}.php") */public function catchEmAllAction($filename) { ob_start(); include $filename.”.php”;

$content = ob_get_clean(); $this->doSomeHeadersStuff(headers_list()); return new Response($content); }

Page 23: From * to Symfony2

Routing: 2 front controllers

Page 24: From * to Symfony2

Two front controllers

/path/to/legacy/public/index.php

/path/to/sf2/web/app.php

Page 25: From * to Symfony2

Easy wayREQUEST

WEB SERVER

FRONT CTRL 1 FRONT CTRL 2

Page 26: From * to Symfony2

Subdomain

http://www.mysite.com

http://new.mysite.com

OLD

NEW

Page 27: From * to Symfony2

Url prefix

http://www.mysite.com/

http://www.mysite.com/new/

OLD

NEW

Page 28: From * to Symfony2

Sf2 proxyREQUEST

WEB SERVER

FRONT CTRL 2 FRONT CTRL 1

Page 29: From * to Symfony2

Event listener

legacy.kernel.listener: class: AppBundle\LegacyBridge\KernelListener tags: - name: kernel.event_listener event: kernel.exception method: onKernelException

Page 30: From * to Symfony2

NotFoundHttpExceptionpublic function onKernelException($event){ $exception = $event->getException(); if ($exception instanceof NotFoundHttpException) { ob_start(); include "/path/to/old/index.php"; $content = ob_get_clean(); $this->doSomeHeadersStuff(headers_list());

$event->setResponse(new Response($content)); } }

Page 31: From * to Symfony2

Database

Page 32: From * to Symfony2

Database

• Cleanup

• Import metadata/structure

• Create entity

• [Add annotation]

Page 33: From * to Symfony2

Metadata

$ php app/console \ doctrine:mapping:import \ --force AppBundle xml

Page 34: From * to Symfony2

Entities

$ php app/console \ doctrine:generate:entities AppBundle

Page 35: From * to Symfony2

Annotation

$ php app/console \ doctrine:mapping:convert annotation ./src

Page 36: From * to Symfony2

Annotation/** * IngredientTranslation * * @ORM\Table(name=“ingredient_translation", * indexes={ * @ORM\Index(name=“IDX_C1A8BF6BF396750”, * columns={“id"}) * }) * @ORM\Entity */ class IngredientTranslation{…}

Page 37: From * to Symfony2

Entitiesclass Wow{ /** * @ORM\Column(name="p0", type="integer") * @ORM\Id */ private $p0;

/** * @ORM\Column(name="p1", type="string", …) */ private $p1; … }

Page 38: From * to Symfony2

Entitiesclass Wow{ /** * @ORM\Column(name="p0", type="integer") * @ORM\Id */ private $id;

/** * @ORM\Column(name="p1", type="string", …) */ private $title; … }

Page 39: From * to Symfony2

Authentication aka

Session

Page 40: From * to Symfony2
Page 41: From * to Symfony2

Login in Sf2 app

Add layer to read Sf2 session

Forge a compatible $_SESSION

or

Page 42: From * to Symfony2

Login in “Old” app

Use preAuthentication

Page 43: From * to Symfony2

SessionBagInterfaceMetadataBag

FlashBag AutoExpireFlashBag

AttributeBag NamespacedAttributeBag

Page 44: From * to Symfony2

$_SESSION (old app logged in)

[ 'App' => [ 'user_id' => 10, ‘username' => 'kea' ] ]

Page 45: From * to Symfony2

$_SESSION (anonym)

[ '_sf2_attributes' => [ ] '_sf2_flashes' => [ ] '_sf2_meta' => [ ... ]]

Page 46: From * to Symfony2

$_SESSION (logged in)

[ '_sf2_attributes' => [ '_security_application' =>

<serialised token> …

] …

]

Page 47: From * to Symfony2

Register bag onKernelRequest

$bag = new NamespacedAttributeBag('App');$bag->setName('App'); $session->registerBag($bag);

Page 48: From * to Symfony2

SimplePreAuthenticatorpublic function createToken( Request $request, $providerKey){ $session = $request->getSession(); $bag = $session->getBag('App'); if (!$bag->has("user_id") || !$bag->has("username")) { throw new BadCredentialsException(‘!'); } …}

Page 49: From * to Symfony2

SimplePreAuthenticatorpublic function createToken( Request $request, $providerKey){ … return new PreAuthenticatedToken( 'anon.', [ "id" => $bag->has("user_id"), "username" => $bag->has("username") ], $providerKey );}

Page 50: From * to Symfony2

SimplePreAuthenticator

public function authenticateToken( TokenInterface $token, UserProviderInterface $userProvider, $providerKey){ $credentials = $token->getCredentials(); $user = $this ->userProvider ->loadUserByIdAndUsername( $credentials[“id"], $credentials[“username"] ); … }

Page 51: From * to Symfony2

The bundle

TheodoEvolutionSessionBundle

Page 52: From * to Symfony2

Alternative way

Single Sign On

Page 53: From * to Symfony2

Templating

Page 54: From * to Symfony2

Templating

Page 55: From * to Symfony2

Rewrite pros

•green field

•no old code to manage

Page 56: From * to Symfony2

Rewrite cons

•data import

•time to market

•two sites to maintain

Page 57: From * to Symfony2

Migration pros

•time to market

•gradual learning

•fade out of old code

•no data migration

Page 58: From * to Symfony2

Migration cons

•spaghetti code for long time

•learn how to pair two technologies

Page 59: From * to Symfony2

Thank You

Page 60: From * to Symfony2

References and credits

https://github.com/wimg/PHPCompatibility https://github.com/LExpress/symfony1 http://symfony.com/doc/current/cookbook/doctrine/reverse_engineering.html https://github.com/theodo/TheodoEvolutionSessionBundle https://github.com/marfillaster/ButterweedSF1EmbedderBundle https://www.flickr.com/photos/clairity/1267539354 https://www.flickr.com/photos/usfwshq/6777513684