Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

De Legacy à Symfony

658 views

Published on

Vous avez déjà travaillé avec de vieux projet PHP (3,4), du “include-ception” ou tout simplement un framework non PSR-0? Voici un retour sur les étapes employé dans différent cas de migration de “legacy” vers Symfony 2.

Published in: Software
  • Be the first to comment

De Legacy à Symfony

  1. 1. DE LEGACY À SYMFONY PHP QUÉBEC 3 MARS 2016 Etienne Lachance @elachance
  2. 2. QUI SUIS-JE Sys admin de formation Programmeur depuis ~10 ans Propriétaire de elcweb.ca Consultation en entreprise Programmation Hébergement spécialisé Fin de l'auto promotion
  3. 3. CONTEXT Evolution d'un projet "Legacy" sans affecter la productivité mais en introduisant les bonne pratique d’un nouveau framework.
  4. 4. PAR LEGACY J'ENTEND peu/pas de documentation peu/pas de tests Code procédural Code spaghetti Duplication de code (copier-coller) Include-ception Couplage de responsabilité ... Non SOLID
  5. 5. OBJECTIF Permet de refactoriser le code petit peu par petit peu mais d'avoir des avantages rapidement.
  6. 6. ATTENTION! IL EST FORTEMENT RECOMMANDÉ D’ÉCRIRE DES TESTS AUTOMATISÉS. PHPUnit Behat
  7. 7. 3 MÉTHODOLOGIES
  8. 8. 1. PARALLEL simple a implémenter (mod_rewrite) aucune communication direct entre les 2 applications utilisation de la BD ou Redis pour l'échange entre les 2 apps peu/pas d'impacte sur l'application 1
  9. 9. 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 Legacy authentification sécurité entre les 2 applications peu/pas d'impacte sur l'application Legacy
  10. 10. 3. INTÉGRATION On veut changer la structure fondamental du code actuel. une seule application OPTION PRÉSENTÉ
  11. 11. QU'EST-CE QUE SYMFONY? Symfony est * une collection de composante un framework applicatif une philosophy une communauté Symfony est a la base un framework HTTP GESTION DES REQUÊTE / RÉPONSE source: http://symfony.com/what-is-symfony
  12. 12. EXEMPLE
  13. 13. STRUCTURE DE FICHIER BONNE PRATIQUE: PLACER LE CODE A L'EXTERIEUR DU RÉPERTOIRE PUBLIQUE.
  14. 14. STRUCTURE RÉVISÉ
  15. 15. MODIFIONS LE CODE
  16. 16. 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 namespace logique basé sur include() / require()
  17. 17. LEGACY CONTROLLER namespace AppBundleController; 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"; }
  18. 18. RÉCAPITULATION déplacer les fichiers a l'extérieur du répertoire publique vérifier si le module exist si le module n'existe pas, retourne une erreur 404 encapsuler les "echo" du code legacy dans un objet Response
  19. 19. PROCHAINE ÉTAPES Authentification/Autorisation (incluant la session) Isolation de la base de donnée (Repository) Vue (Templates)
  20. 20. AUTHENTIFICATION/AUTORISATION AUTHENTIFICATION Qui es-tu ? AUTORISATION Quels sont les accès / droits
  21. 21. MAINTENANT DANS SYMFONY
  22. 22. UTILISATEUR Implement UserInterface <?php namespace AppBundleSecurityUser; use ... class User implements UserInterface { private $username; private $password; private $salt prirate $roles; ... }
  23. 23. PROVIDER Est responsable d'aller chercher l'utilisateur Implement UserProviderInterface <?php namespace AppBundleSecurityUser; 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 = '...';
  24. 24. ENCODER Responsable d'encoder et de valider un mot de passe <?php namespace AppBundleSecurityEncoder; use SymfonyComponentSecurityCoreEncoderBasePasswordEncoder; class LegacyMd5Encoder extends BasePasswordEncoder { public function isPasswordValid($encoded, $raw, $salt = null) :bool { return $this->comparePasswords(strtolower($encoded), strtolower($this->encodePassword($raw, $ } /** * @param string $raw * @param null|string $salt * * @return string
  25. 25. CONFIGURATION app/config/services.yml services: app.user_provider: class: AppBundleSecurityUserUserProvider app.security.encoder.md5: class: AppBundleSecurityEncoderLegacyMd5Encoder app/config/security.yml security: encoders: AppBundleSecurityUserUser: id: app.security.encoder.md5 providers: legacy: id: app.user_provider firewall: main: pattern: ^/ http_basic: ~
  26. 26. RECOMMANDATION Utilisation d'un algorithme plus sécuritaire comme bcrypt ou sha512 Convertion des mots de passes "on the fly"
  27. 27. DOCTRINE Permet de représenter en Objet et non en Base de donnée relationnel.
  28. 28. DOCTRINE / REPOSITORY Dans le contexte de Doctrine, un Repository est utilisé pour allez chercher l'information Centraliser les requêtes SQL Isoler les requêtes du "controlleur" Classifier par context d'objet (Utilisateur/Produit/Client)
  29. 29. 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);
  30. 30. 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
  31. 31. REPOSITORY namespace AppBundleEntity; use DoctrineORMEntityRepository; 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
  32. 32. UTILISATION DANS UN CONTROLLEUR class 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()); } }
  33. 33. QUESTIONS ?
  34. 34. MERCI! http://elcweb.ca http://etiennelachance.com @elachance https://github.com/estheban

×