de legacy à symfony

34
DE LEGACY À SYMFONY PHP QUÉBEC 3 MARS 2016 Etienne Lachance @elachance

Upload: elcwebca

Post on 22-Feb-2017

418 views

Category:

Software


0 download

TRANSCRIPT

Page 1: De Legacy à Symfony

DE LEGACY À SYMFONYPHP QUÉBEC

3 MARS 2016Etienne Lachance

@elachance

Page 2: De Legacy à Symfony

QUI SUIS-JESys admin de formationProgrammeur depuis ~10 ansPropriétaire de elcweb.ca

Consultation en entrepriseProgrammationHébergement spécialiséFin de l'auto promotion

Page 3: De Legacy à Symfony

CONTEXTEvolution d'un projet "Legacy" sans affecter la productivité mais en

introduisant les bonne pratique d’un nouveau framework.

Page 4: De Legacy à Symfony

PAR LEGACY J'ENTENDpeu/pas de documentationpeu/pas de testsCode procéduralCode spaghettiDuplication de code (copier-coller)Include-ceptionCouplage de responsabilité... Non SOLID

Page 5: De Legacy à Symfony

OBJECTIFPermet de refactoriser le code petit peu par petit peu mais d'avoir des

avantages rapidement.

Page 6: De Legacy à Symfony

ATTENTION!IL EST FORTEMENT RECOMMANDÉ D’ÉCRIRE DES TESTS

AUTOMATISÉS.PHPUnitBehat

Page 7: De Legacy à Symfony

3 MÉTHODOLOGIES

Page 8: De Legacy à Symfony

1. PARALLEL

simple a implémenter (mod_rewrite)aucune communication direct entre les 2 applicationsutilisation de la BD ou Redis pour l'échange entre les 2 appspeu/pas d'impacte sur l'application 1

Page 9: De Legacy à Symfony

2. PROXY

l'utilisateur voie uniquement une application (Symfony)necessite plus de travail pour la mise en place

"wrapper" pour les requêtes a l'application Legacyauthentificationsécurité entre les 2 applications

peu/pas d'impacte sur l'application Legacy

Page 10: De Legacy à Symfony

3. INTÉGRATION

On veut changer la structure fondamental du code actuel.une seule application

OPTION PRÉSENTÉ

Page 11: De Legacy à Symfony

QU'EST-CE QUE SYMFONY?Symfony est *

une collection de composanteun framework applicatifune philosophyune communauté

Symfony est a la base un framework HTTP

GESTION DES REQUÊTE / RÉPONSEsource: http://symfony.com/what-is-symfony

Page 12: De Legacy à Symfony

EXEMPLE

Page 13: De Legacy à Symfony

STRUCTURE DE FICHIER

BONNE PRATIQUE: PLACER LE CODE A L'EXTERIEUR DU RÉPERTOIRE PUBLIQUE.

Page 14: De Legacy à Symfony

STRUCTURE RÉVISÉ

Page 15: De Legacy à Symfony

MODIFIONS LE CODE

Page 16: De Legacy à Symfony

EXEMPLE DE TYPE "INCLUDE-CEPTION"<?php // index.php

include("includes/common.php"); include("includes/config.php");

$mod = $_GET['mod']; if ($mod=="" || !preg_match('/̂[A-Za-z1-90_]+$/Ui',$mod)) $mod = "dashboard";

include ("modules/".$mod.".php");

aucun namespacelogique basé sur include() / require()

Page 17: De Legacy à Symfony

LEGACY CONTROLLERnamespace AppBundle\Controller; use ...;

class LegacyController extends Controller { /** @Route("/index.php") */ public function legacyAction() { // __DIR__ == 'src/AppBundle/Controller' include __DIR__ . '/../includes/common.php'; include __DIR__ . '/../includes/config.php';

// @todo: renommé $mod pour $module $mod = $_GET['mod']; if ($mod=="" || !preg_match('/̂[A-Za-z1-90_]+$/Ui', $mod)) { $mod = "dashboard"; }

Page 18: De Legacy à Symfony

RÉCAPITULATIONdéplacer les fichiers a l'extérieur du répertoire publiquevérifier si le module existsi le module n'existe pas, retourne une erreur 404encapsuler les "echo" du code legacy dans un objet Response

Page 19: De Legacy à Symfony

PROCHAINE ÉTAPESAuthentification/Autorisation (incluant la session)Isolation de la base de donnée (Repository)Vue (Templates)

Page 20: De Legacy à Symfony

AUTHENTIFICATION/AUTORISATIONAUTHENTIFICATION

Qui es-tu ?

AUTORISATIONQuels sont les accès / droits

Page 21: De Legacy à Symfony

MAINTENANT DANS SYMFONY

Page 22: De Legacy à Symfony

UTILISATEURImplement UserInterface

<?php

namespace AppBundle\Security\User;

use ...

class User implements UserInterface { private $username; private $password; private $salt prirate $roles;

... }

Page 23: De Legacy à Symfony

PROVIDEREst responsable d'aller chercher l'utilisateur

Implement UserProviderInterface

<?php

namespace AppBundle\Security\User;

use ...

class UserProvider implements UserProviderInterface { public function loadUserByUsername($username) { // aller chercher l'utilisateur // dans la base de donnée, le webservice, ... $userData = ... // pretend it returns an array on success, false if there is no user

if ($userData) { $password = '...';

Page 24: De Legacy à Symfony

ENCODERResponsable d'encoder et de valider un mot de passe

<?php

namespace AppBundle\Security\Encoder;

use Symfony\Component\Security\Core\Encoder\BasePasswordEncoder;

class LegacyMd5Encoder extends BasePasswordEncoder { public function isPasswordValid($encoded, $raw, $salt = null) :bool { return $this->comparePasswords(strtolower($encoded), strtolower($this->encodePassword($raw, $salt))); }

/** * @param string $raw * @param null|string $salt * * @return string

Page 25: De Legacy à Symfony

CONFIGURATIONapp/config/services.yml

services: app.user_provider: class: AppBundle\Security\User\UserProvider app.security.encoder.md5: class: AppBundle\Security\Encoder\LegacyMd5Encoder

app/config/security.yml

security: encoders: AppBundle\Security\User\User: id: app.security.encoder.md5 providers: legacy: id: app.user_provider firewall: main: pattern: ̂/ http_basic: ~

Page 26: De Legacy à Symfony

RECOMMANDATIONUtilisation d'un algorithme plus sécuritaire comme bcrypt ou sha512

Convertion des mots de passes "on the fly"

Page 27: De Legacy à Symfony

DOCTRINEPermet de représenter en Objet et non en Base de donnée relationnel.

Page 28: De Legacy à Symfony

DOCTRINE / REPOSITORYDans le contexte de Doctrine, un Repository est utilisé pour allez chercher

l'information

Centraliser les requêtes SQLIsoler les requêtes du "controlleur"Classifier par context d'objet (Utilisateur/Produit/Client)

Page 29: De Legacy à Symfony

LEGACY<?php // ...

$conn = mysql_connect($db_host, $db_user, $db_password);

if (!$conn) { echo "Unable to connect to DB: " . mysql_error(); exit; }

if (!mysql_select_db($dbname)) { echo "Unable to select mydbname: " . mysql_error(); exit; }

$sql = "SELECT * FROM products WHERE category = ".mysql_real_escape_string($_GET['cat']).";"

$result = mysql_query($sql);

Page 30: De Legacy à Symfony

GÉNÉRATION D'ENTITÉ A PARTIR D'UNE BASE DE DONNÉEXISTANTE

$ php bin/console doctrine:mapping:import --force AcmeBlogBundle xml $ php bin/console doctrine:mapping:convert annotation ./src $ php bin/console doctrine:generate:entities AcmeBlogBundle

http://symfony.com/doc/current/cookbook/doctrine/reverse_engineering.html

Page 31: De Legacy à Symfony

REPOSITORYnamespace AppBundle\Entity;

use Doctrine\ORM\EntityRepository;

class ProductRepository extends EntityRepository { public function findByCategory($categoryId) { $sql = "SELECT * FROM products WHERE category = ".mysql_real_escape_string($categoryId

$stmt = $this->getEntityManager()->getConnection()->prepare($sql); $stmt->execute();

return $stmt->findAll(); } }

RawSQLTrait: https://gist.github.com/estheban/3eae41271f6cf5f3180a

Page 32: De Legacy à Symfony

UTILISATION DANS UN CONTROLLEURclass ProductController extends Controller { /** * @Route("/product.php/category/{id}") */ public function productByCategory(Category $category) { // throw 404 si pas de Catégorie trouvée

$entityManager = $this->getDoctrine()->getManager();

return $entityManager ->getRepository("AppBundle:Product") ->findByCategory($category->getId()); } }

Page 33: De Legacy à Symfony

QUESTIONS ?

Page 34: De Legacy à Symfony

MERCI!http://elcweb.cahttp://etiennelachance.com@elachancehttps://github.com/estheban