codemotion workshop

76
High Performance Web Apps con PHP e Symfony 2 di Giorgio Cefaro ed Eugenio Pombi

Upload: eugenio-pombi

Post on 27-Jan-2015

130 views

Category:

Technology


1 download

DESCRIPTION

slides of the workshop held at codemotion rome 2013

TRANSCRIPT

Page 1: Codemotion workshop

High Performance Web Apps con PHP e Symfony 2

di Giorgio Cefaro ed Eugenio Pombi

Page 2: Codemotion workshop

Giorgio Cefaro

@giorrrgiogiorgiocefaro.com

Page 3: Codemotion workshop

Eugenio Pombi

@euxpomnerd2business.net

Page 4: Codemotion workshop

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

Page 5: Codemotion workshop

Request > Response

Page 6: Codemotion workshop

http://symfony.com/download

Page 7: Codemotion workshop

get the git repo/home/sf2/pugx_book

git clone [email protected]:eux/pugx_book_2.git

git tag -l

git checkout {nomeTag}

git stash

nerd2business.net

Page 8: Codemotion workshop

http://pugx-book.localhost/config.php

Page 9: Codemotion workshop

tag cap1

git checkout cap1

Page 10: Codemotion workshop

parameters-dist.ymlparameters: database_driver: pdo_mysql database_host: 127.0.0.1 database_port: ~ database_name: pugx_book database_user: root database_password: sf2

mailer_transport: smtp mailer_host: 127.0.0.1 mailer_user: ~ mailer_password: ~

locale: en secret: ThisTokenIsNotSoSecretChangeIt

Page 11: Codemotion workshop

composercurl -s https://getcomposer.org/installer | php

composer.jsoncomposer.lock

./composer.phar update

./composer.phar install

Page 12: Codemotion workshop

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>

Page 13: Codemotion workshop

/etc/hosts

127.0.0.1 pugx-book.localhost

Page 14: Codemotion workshop

struttura

Page 15: Codemotion workshop

bundle

Page 16: Codemotion workshop

tag cap2

git checkout cap2

Page 17: Codemotion workshop

il nostro bundlephp 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

Page 18: Codemotion workshop

DefaultControllerTest.php

DefaultControllerTest.php

src/PUGX/BookBundle/Tests/Controller/DefaultControllerTest.php

phpunit -c app/

Page 19: Codemotion workshop

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

Page 20: Codemotion workshop

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 }

Page 21: Codemotion workshop

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

Page 22: Codemotion workshop

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

Page 23: Codemotion workshop

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:nth-child(1)')->text());

Page 24: Codemotion workshop

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

Page 25: Codemotion workshop

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:nth-child(1)')->text());

Page 26: Codemotion workshop

DefaultControllerTest.php

DefaultControllerTest.php

src/PUGX/BookBundle/Tests/Controller/DefaultControllerTest.php

phpunit -c app/

Page 27: Codemotion workshop

DefaultControllerTest.php

DefaultControllerTest.php

TEST ROSSI

There was 1 error:

1) PUGX\BookBundle\Tests\Controller\DefaultControllerTest::testIndex

InvalidArgumentException: The current node list is empty.

/home/eux/Documents/www/symfony2/pugx_book/vendor/symfony/symfony/src/Symfony/Component/DomCrawler/Crawler.php:468

/home/eux/Documents/www/symfony2/pugx_book/src/PUGX/BookBundle/Tests/Controller/DefaultControllerTest.php:16

FAILURES!

Tests: 1, Assertions: 1, Failures: 1.

Page 28: Codemotion workshop

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>

Page 29: Codemotion workshop

DefaultControllerTest.php

DefaultControllerTest.php

src/PUGX/BookBundle/Tests/Controller/DefaultControllerTest.php

phpunit -c app/

Page 30: Codemotion workshop

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)

Page 31: Codemotion workshop

tag cap3

git stash

git checkout cap3

Page 32: Codemotion workshop

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.

Page 33: Codemotion workshop

DefaultControllerTest.php

Il test

Scriviamo innanzi tutto il test testBooks() insrc/PUGX/BookBundle/Tests/Controller/DefaultControllerTest.php

Page 34: Codemotion workshop

DefaultControllerTest.php

l'entità Book

La struttura dati che rappresenta il nostro libro è l'entità Book, definita in:src/PUGX/BookBundle/Entity/Book.php

Page 35: Codemotion workshop

DefaultControllerTest.php

la nuova rotta

Aggiungiamo una nuova rotta che risponderà all'url /books

Page 36: Codemotion workshop

DefaultControllerTest.php

la nuova action

Aggiungiamo un metodo booksAction al DefaultController in cui ci limiteremo a creare tre instanze di Book, passandole al twig

Page 37: Codemotion workshop

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

Page 38: Codemotion workshop

tag cap4

git checkout cap4

Page 39: Codemotion workshop

Doctrine - ORMObject Relational Mapping

class Book { public $title; public $author; public $publicationDate}

Page 40: Codemotion workshop

Doctrine DBAL

PostgreSQL MySQL SQLite

PDO

Doctrine DBAL

Application

Page 41: Codemotion workshop

Book entity/** * @ORM\Entity * @ORM\Table(name="book") */class Book{ [...] }

src/PUGX/BookBundle/Entity/Book.php

http://symfony.com/it/doc/2.3/book/doctrine.html#book-doctrine-field-types

Page 42: Codemotion workshop

parameters.yml/app/config/parameters.yml

database_driver: pdo_mysqldatabase_host: 127.0.0.1database_port: ~database_name: pugx_bookdatabase_user: rootdatabase_password: ~

Page 43: Codemotion workshop

Doctrine commandsphp app/console doctrine:database:create

php app/console doctrine:database:drop --force

php app/console doctrine:schema:create

Page 44: Codemotion workshop

Doctrine migrationsdirectory:/app/DoctrineMigrations

table:migration_versions

php app/console doctrine:migrations:diffphp app/console doctrine:migrations:migratephp app/console doctrine:migrations:execute --up NNNphp app/console doctrine:migrations:execute --down NNN

Page 45: Codemotion workshop

Doctrine fixturessrc/PUGX/BookBundle/DataFixtures/ORM/LoadBookData.php

php app/console doctrine:fixtures:load

Page 46: Codemotion workshop

DefaultControllerTest.php/src/PUGX/BookBundle/Tests/Controller/DefaultControllerTest.php

Controlliamo che i libri siano in ordine alfabetico

Page 47: Codemotion workshop

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) );}

Page 48: Codemotion workshop

DefaultControllerTest.php/src/PUGX/BookBundle/Tests/Controller/DefaultControllerTest.php

Aggiungiamo il test per una pagina di dettaglio (o 404)

Page 49: Codemotion workshop

rotta - action - template/src/PUGX/BookBundle/Resources/config/routing.yml

/src/PUGX/BookBundle/Controller/DefaultController.php

/src/PUGX/BookBundle/Resources/views/Default/bookDetail.html.twig

Page 50: Codemotion workshop

tag cap5

git checkout cap5

Page 51: Codemotion workshop

doctrine - approfondimentiAuthor è un campo testualeUn autore è associato a più libriSpostiamo l'autore in una entità separata.

php app/console doctrine:generate:entity --entity="PUGXBookBundle:Author" --fields="name:string(255) surname:string(255) bio:text"

Page 52: Codemotion workshop

Author entity/** * @ORM\Entity * @ORM\Table(name="author") */class Author{ [...] }

src/PUGX/BookBundle/Entity/Author.php

http://symfony.com/it/doc/2.3/book/doctrine.html#book-doctrine-field-types

Page 53: Codemotion workshop

doctrine - associazioni

Per definire l'associazione tra Book e Author utilizziamo le annotazioni di Doctrine OneToMany(lato Author) e ManyToOne(lato Book)

Page 54: Codemotion workshop

doctrine - associazioniin src/PUGX/BookBundle/Entity/Author.php

/**

* @ORM\OneToMany(targetEntity="PUGX\BookBundle\Entity\Book", mappedBy="author")

*/

private $books;

aggiungendo i metodi addBook, getBooks, setBooks e removeBook

Page 55: Codemotion workshop

doctrine - associazioniin src/PUGX/BookBundle/Entity/Book.php

/**

* @ORM\ManyToOne(targetEntity="PUGX\BookBundle\Entity\Author", inversedBy="books")

**/

protected $author;

aggiungendo i metodi setAuthor e getAuthor

Page 56: Codemotion workshop

doctrine - associazioniOsservazione

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.

Page 57: Codemotion workshop

doctrine - migrazionePer poter allineare il database ai cambiamenti, è necessario generare e applicare una nuova migrazione:

php app/console doctrine:migrations:diffphp app/console doctrine:migrations:migrate

Page 58: Codemotion workshop

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;}

Page 59: Codemotion workshop

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 }}

Page 60: Codemotion workshop

problema!!!

Page 61: Codemotion workshop

causa

Page 62: Codemotion workshop

profiler$client->enableProfiler();

[...]

$nbQuery = $client->getProfile()->getCollector('db')->getQueryCount();

$this->assertEquals(1, $nbQuery);

Page 63: Codemotion workshop

custom repository/** * * @ORM\Entity(repositoryClass="PUGX\BookBundle\Repository\BookRepository") * @ORM\Table(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();

Page 64: Codemotion workshop

DQLpublic 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();}

Page 65: Codemotion workshop

tag cap6

git checkout cap6

Page 66: Codemotion workshop

DefaultControllerTest

testCreate

Page 67: Codemotion workshop

form type

/src/PUGX/BookBundle/Form/Type/BookType.php

Page 68: Codemotion workshop

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 }

Page 69: Codemotion workshop

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 }

Page 70: Codemotion workshop

form action/src/PUGX/BookBundle/Controller/DefaultController.php

public function bookCreateAction(Request $request) { ...}

Page 71: Codemotion workshop

twig form

/BookBundle/Resources/views/Default/bookCreate.html.twig

Page 72: Codemotion workshop

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 %}

Page 73: Codemotion workshop

tearDown

Eliminazione del record inserito con il test

Page 74: Codemotion workshop

tag cap7

git checkout cap7

Page 75: Codemotion workshop

security

Page 76: Codemotion workshop

extra

git checkout extra1git checkout extra2git checkout extra3