Codemotion workshop

1,144 views

Published on

slides of the workshop held at codemotion rome 2013

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
1,144
On SlideShare
0
From Embeds
0
Number of Embeds
4
Actions
Shares
0
Downloads
8
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Codemotion workshop

  1. 1. High Performance Web Apps con PHP e Symfony 2 di Giorgio Cefaro ed Eugenio Pombi
  2. 2. Giorgio Cefaro @giorrrgio giorgiocefaro.com
  3. 3. Eugenio Pombi @euxpom nerd2business.net
  4. 4. Symfony 2 First, Symfony2 is a reusable set of standalone, decoupled, and cohesive PHP components that solve common web development problems. Then, based on these components, Symfony2 is also a full-stack web framework. Fabien Potencier
  5. 5. Request > Response
  6. 6. http://symfony.com/download
  7. 7. get the git repo /home/sf2/pugx_book git clone git@bitbucket.org:eux/pugx_book_2.git git tag -l git checkout {nomeTag} git stash nerd2business.net
  8. 8. http://pugx-book.localhost/config.php
  9. 9. tag cap1 git checkout cap1
  10. 10. parameters-dist.yml parameters: database_driver: pdo_mysql database_host: 127.0.0.1 database_port: ~ database_name: database_user: pugx_book root database_password: sf2 mailer_transport: smtp mailer_host: 127.0.0.1 mailer_user: ~ mailer_password: ~ locale: en secret: ThisTokenIsNotSoSecretChangeIt
  11. 11. composer curl -s https://getcomposer.org/installer | php composer.json composer.lock ./composer.phar update ./composer.phar install
  12. 12. virtual host <VirtualHost *:80> ServerName pugx-book.localhost DocumentRoot "/PATH TO PROJECT/pugx_book/web" DirectoryIndex index.php <Directory "/PATH TO PROJECT/pugx_book/web"> AllowOverride All Require all granted </Directory> </VirtualHost>
  13. 13. /etc/hosts 127.0.0.1 pugx-book.localhost
  14. 14. struttura
  15. 15. bundle
  16. 16. tag cap2 git checkout cap2
  17. 17. il nostro bundle php app/console generate:bundle --namespace=PUGX/BookBundle --format=yml Bundle namespace [PUGX/BookBundle]: Bundle name [PUGXBookBundle]: Target directory [/home/USERNAME/PATH/pugx_book/src]: Configuration format (yml, xml, php, or annotation) [yml]: Do you want to generate the whole directory structure [no]? yes
  18. 18. DefaultControllerTest.php DefaultControllerTest.php src/PUGX/BookBundle/Tests/Controller/ DefaultControllerTest.php phpunit -c app/
  19. 19. front controller /web/app.php /web/app_dev.php /app/config/config.yml /app/config/config_dev.yml /app/config/config_prod.yml /app/config/config_test.yml
  20. 20. routing /app/config/routing.yml pugx_book: resource: "@PUGXBookBundle/Resources/config/routing.yml" prefix: / /src/PUGX/BookBundle/Resources/config/routing.yml pugx_book_homepage: pattern: / defaults: { _controller: PUGXBookBundle:Default:index }
  21. 21. controller In genere costituito da una classe che raggruppa una serie di azioni definite attraverso metodi pubblici. Il nostro primo controller: src/PUGX/BookBundle/Controller/DefaultController.php
  22. 22. twig return $this->render('PUGXBookBundle:Default:index.html.twig'); PUGXBookBundle: <NomeVendor><NomeBundle> Default: <NomeController> index.html.twig: <NomeTemplate> //src/PUGX/BookBundle/Resources/views/Default/index.html.twig Hello world! http://symfony.com/it/doc/2.3/book/templating.html
  23. 23. yay! live coding //src/PUGX/BookBundle/Tests/Controller/DefaultControllerTest.php $this->assertTrue($client->getResponse()->isSuccessful()); $this->assertRegExp("/Welcome/i", $crawler->filter('h1')->text()); $this->assertTrue($crawler->filter('p')->count() > 0); //nav bar $this->assertTrue($crawler->filter('.navbar')->count() > 0); $this->assertEquals(1, $crawler->filter('.navbar > li')->count()); $this->assertRegExp("/home/i", $crawler->filter('.navbar > li:nthchild(1)')->text());
  24. 24. PHPUnit asserts verifichiamo che la risposta sia valida $this->assertTrue($client->getResponse()->isSuccessful()); ci assicuriamo che l’elemento h1 contenga la parola "Welcome": $this->assertRegExp("/Welcome/i", $crawler->filter('h1')->text()); $crawler è un'istanza del componente DomCrawler di Sf2, permette di manipolare documenti XML e HTML attraverso xpath e css selector: http://symfony.com/doc/2.3/components/dom_crawler.html
  25. 25. PHPUnit asserts ci assicuriamo che ci sia almeno un elemento p nella pagina di risposta: $this->assertTrue($crawler->filter('p')->count() > 0); verifichiamo che ci sia un oggetto del DOM che abbia la classe css navbar: $this->assertTrue($crawler->filter('.navbar')->count() > 0); verifichiamo che la navbar contenga un solo elemento li: $this->assertEquals(1, $crawler->filter('.navbar > li')->count()); infine verifichiamo che il primo elemento li di navbar contenga il testo home $this->assertRegExp("/home/i", $crawler->filter('.navbar > li:nthchild(1)')->text());
  26. 26. DefaultControllerTest.php DefaultControllerTest.php src/PUGX/BookBundle/Tests/Controller/ DefaultControllerTest.php phpunit -c app/
  27. 27. DefaultControllerTest.php DefaultControllerTest.php TEST ROSSI There was 1 error: 1) PUGXBookBundleTestsControllerDefaultControllerTest::testIndex InvalidArgumentException: The current node list is empty. /home/eux/Documents/www/symfony2/pugx_book/vendor/symfony/symfony/src/Symfony/Component/DomCrawler/Cra wler.php:468 /home/eux/Documents/www/symfony2/pugx_book/src/PUGX/BookBundle/Tests/Controller/DefaultControllerTest.php: 16 FAILURES! Tests: 1, Assertions: 1, Failures: 1.
  28. 28. make it GREEN //src/PUGX/BookBundle/Resources/views/Default/index.html.twig <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>PUGX Book</title> </head> <body> <div id="sidebar"> <ul class="navbar"> <li><a href="/">Home</a></li> </ul> </div> <div id="content"> <h1>Welcome on PUGX Book</h1> <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus ultrices, nisi quis porta fermentum, magna ligula suscipit metus, quis blandit leo urna non diam. Sed non dui dui, quis porttitor massa. Phasellus convallis porta leo, sed vehicula eros ultrices sit amet.</p> </div> </body> </html>
  29. 29. DefaultControllerTest.php DefaultControllerTest.php src/PUGX/BookBundle/Tests/Controller/ DefaultControllerTest.php phpunit -c app/
  30. 30. DefaultControllerTest.php DefaultControllerTest.php TEST VERDI PHPUnit 3.6.11 by Sebastian Bergmann. Configuration read from /home/giorgio/Progetti/codemotion/pugx_book/app/phpunit.xml.dist . Time: 11 seconds, Memory: 17.50Mb OK (1 test, 6 assertions)
  31. 31. tag cap3 git stash git checkout cap3
  32. 32. DefaultControllerTest.php un elenco di libri Vogliamo aggiungere una pagina che contiene una lista di libri, ognuno con informazioni relative all'autore e alla data di pubblicazione.
  33. 33. DefaultControllerTest.php Il test Scriviamo innanzi tutto il test testBooks() in src/PUGX/BookBundle/Tests/Controller/DefaultControllerTest. php
  34. 34. DefaultControllerTest.php l'entità Book La struttura dati che rappresenta il nostro libro è l'entità Book, definita in: src/PUGX/BookBundle/Entity/Book.php
  35. 35. DefaultControllerTest.php la nuova rotta Aggiungiamo una nuova rotta che risponderà all'url /books
  36. 36. DefaultControllerTest.php la nuova action Aggiungiamo un metodo booksAction al DefaultController in cui ci limiteremo a creare tre instanze di Book, passandole al twig
  37. 37. DefaultControllerTest.php il nuovo template Creiamo un nuovo twig in src/PUGX/BookBundle/Resources/views/Default/books.html.twig e stampiamo la lista di libri in una tabella Ereditarietà dei template
  38. 38. tag cap4 git checkout cap4
  39. 39. Doctrine - ORM Object Relational Mapping class Book { public $title; public $author; public $publicationDate }
  40. 40. Doctrine DBAL Application Doctrine DBAL PDO PostgreSQL MySQL SQLite
  41. 41. Book entity /** * @ORMEntity * @ORMTable(name="book") */ class Book { [...] } src/PUGX/BookBundle/Entity/Book.php http://symfony.com/it/doc/2.3/book/doctrine.html#book-doctrine-field-types
  42. 42. parameters.yml /app/config/parameters.yml database_driver: pdo_mysql database_host: 127.0.0.1 database_port: ~ database_name: pugx_book database_user: root database_password: ~
  43. 43. Doctrine commands php app/console doctrine:database:create php app/console doctrine:database:drop --force php app/console doctrine:schema:create
  44. 44. Doctrine migrations directory: /app/DoctrineMigrations table: migration_versions php app/console doctrine:migrations:diff php app/console doctrine:migrations:migrate php app/console doctrine:migrations:execute --up NNN php app/console doctrine:migrations:execute --down NNN
  45. 45. Doctrine fixtures src/PUGX/BookBundle/DataFixtures/ORM/LoadBookData.php php app/console doctrine:fixtures:load
  46. 46. DefaultControllerTest.php /src/PUGX/BookBundle/Tests/Controller/DefaultControllerTest.php Controlliamo che i libri siano in ordine alfabetico
  47. 47. Query con doctrine /src/PUGX/BookBundle/Controller/DefaultController.php public function booksAction() { $em = $this->getDoctrine()->getManager(); $books = $em->getRepository('PUGXBookBundle:Book')->findBy( array(), array('title' => 'ASC') ); return $this->render('PUGXBookBundle:Default:books.html.twig', array('books' => $books) ); }
  48. 48. DefaultControllerTest.php /src/PUGX/BookBundle/Tests/Controller/DefaultControllerTest.php Aggiungiamo il test per una pagina di dettaglio (o 404)
  49. 49. rotta - action - template /src/PUGX/BookBundle/Resources/config/routing.yml /src/PUGX/BookBundle/Controller/DefaultController.php /src/PUGX/BookBundle/Resources/views/Default/bookDeta il.html.twig
  50. 50. tag cap5 git checkout cap5
  51. 51. doctrine - approfondimenti Author è un campo testuale Un autore è associato a più libri Spostiamo l'autore in una entità separata. php app/console doctrine:generate:entity -entity="PUGXBookBundle:Author" --fields="name: string(255) surname:string(255) bio:text"
  52. 52. Author entity /** * @ORMEntity * @ORMTable(name="author") */ class Author { [...] } src/PUGX/BookBundle/Entity/Author.php http://symfony.com/it/doc/2.3/book/doctrine.html#book-doctrine-field-types
  53. 53. doctrine - associazioni Per definire l'associazione tra Book e Author utilizziamo le annotazioni di Doctrine OneToMany(lato Author) e ManyToOne(lato Book)
  54. 54. doctrine - associazioni in src/PUGX/BookBundle/Entity/Author.php /** * @ORMOneToMany(targetEntity="PUGXBookBundleEntityBook", mappedBy="author") */ private $books; aggiungendo i metodi addBook, getBooks, setBooks e removeBook
  55. 55. doctrine - associazioni in src/PUGX/BookBundle/Entity/Book.php /** * @ORMManyToOne(targetEntity="PUGXBookBundleEntityAuthor", inversedBy="books") **/ protected $author; aggiungendo i metodi setAuthor e getAuthor
  56. 56. doctrine - associazioni Osservazione Doctrine nasconde la logica dell'associazione a livello database, in cui l'associazione è definita da un campo author_id della tabella book e una foreign key. La parte inversa dell'associazione è ricostruita automaticamente da Doctrine.
  57. 57. doctrine - migrazione Per poter allineare il database ai cambiamenti, è necessario generare e applicare una nuova migrazione: php app/console doctrine:migrations:diff php app/console doctrine:migrations:migrate
  58. 58. doctrine - fixtures /src/PUGX/BookBundle/DataFixtures/ORM/LoadAuthorData.php elemento $this->addReference('author-beck', $author); riferimento $this->getReference('author-beck') public function getOrder() { return 1; }
  59. 59. template /src/PUGX/BookBundle/Resources/views/Default/books.html.twig /src/PUGX/BookBundle/Resources/views/Default/bookDetail.html.twig {{ book.author.name }} {{ book.author.surname }}
  60. 60. problema!!!
  61. 61. causa
  62. 62. profiler $client->enableProfiler(); [...] $nbQuery = $client->getProfile()->getCollector('db')>getQueryCount(); $this->assertEquals(1, $nbQuery);
  63. 63. custom repository /** * * @ORMEntity(repositoryClass="PUGXBookBundleRepositoryBookRepository") * @ORMTable(name="book") */ class Book /src/PUGX/BookBundle/Repository/BookRepository.php /src/PUGX/BookBundle/Tests/Repository/BookRepositoryTest.php /src/PUGX/BookBundle/Controller/DefaultController.php $books = $em->getRepository('PUGXBookBundle:Book')>findAllWithAuthors();
  64. 64. DQL public function findAllWithAuthors() { $query = $this->getEntityManager() ->createQuery(' SELECT b, a FROM PUGXBookBundle:Book b INNER JOIN b.author a ORDER BY b.title ASC '); return $query->getResult(); }
  65. 65. tag cap6 git checkout cap6
  66. 66. DefaultControllerTest testCreate
  67. 67. form type /src/PUGX/BookBundle/Form/Type/BookType.php
  68. 68. routing problem /src/PUGX/BookBundle/Resources/config/routing.yml pugx_book_detail: pattern: /books/{bookId} defaults: { _controller: PUGXBookBundle:Default:bookDetail } pugx_book_create: pattern: /books/create defaults: { _controller: PUGXBookBundle:Default:bookCreate }
  69. 69. solution /src/PUGX/BookBundle/Resources/config/routing.yml pugx_book_detail: pattern: /books/{bookId} defaults: { _controller: PUGXBookBundle:Default:bookDetail } requirements: bookId: d+ pugx_book_create: pattern: /books/create defaults: { _controller: PUGXBookBundle:Default:bookCreate }
  70. 70. form action /src/PUGX/BookBundle/Controller/DefaultController.php public function bookCreateAction(Request $request) { ... }
  71. 71. twig form /BookBundle/Resources/views/Default/bookCreate.html. twig
  72. 72. flash messages $this->get('session')->getFlashBag()->add('notice', 'Book successfully created'); {% for flashMessage in app.session.flashbag.get('notice') %} <div class="notice"> {{ flashMessage }} </div> {% endfor %}
  73. 73. tearDown Eliminazione del record inserito con il test
  74. 74. tag cap7 git checkout cap7
  75. 75. security
  76. 76. extra git checkout extra1 git checkout extra2 git checkout extra3

×