symfony war stories

42
Symfony War Stories SensioLabsUK Jakub Zalas UK Symfony Meetup November, 2012 http://www.rgbstock.com/bigphoto/mhY2DCY

Upload: jakub-zalas

Post on 11-Jun-2015

3.953 views

Category:

Technology


3 download

DESCRIPTION

UK Symfony Meetup, November 2012 Original presentation: https://docs.google.com/presentation/pub?id=1PLcqTby6yqSbfWlMIDHknH852DU6DO6OAgQJOtSEdsg&start=false&loop=false&delayms=3000

TRANSCRIPT

Page 1: Symfony War Stories

SymfonyWar Stories

SensioLabsUK

Jakub Zalas

UK Symfony Meetup

November, 2012

http://www.rgbstock.com/bigphoto/mhY2DCY

Page 2: Symfony War Stories

Jakub Zalas a.k.a. Kuba

○ Twitter: @jakub_zalas○ Blog: http://zalas.eu○ Github: @jakzal

○ Remembers symfony 1.0 (2007)

○ Open Source contributor○ BDD advocate○ Works at Sensio Labs UK○ ZCE & Sensio Labs

Certified Symfony Developer

Page 3: Symfony War Stories

Symfony War Stories

● Bundling the code

● Thinking outside of the bundle

● Being lazy

● Learning your stuff

● Keeping your playground clean

● Building the quality in

Page 4: Symfony War Stories

Bundling the code

http://www.rgbstock.com/bigphoto/mfXkYUq

Page 5: Symfony War Stories

VS

Page 6: Symfony War Stories

Whenever in doubt...

● Start simple and let the design emerge● Extract bundles when you need to reuse it

or you see it would improve clarity● Avoid two-way dependencies between

bundles

Page 7: Symfony War Stories

Thinking outside of

the bundle

http://www.rgbstock.com/bigphoto/mfBYR2S

Page 8: Symfony War Stories

VS

Page 9: Symfony War Stories

To keep your design clean...

● Treat bundles as an integration layer between PHP libraries and the Symfony framework

● In your libraries, avoid dependencies on

bundles

Page 10: Symfony War Stories

Being lazy

http://www.sxc.hu/photo/858871

Page 11: Symfony War Stories

There's a bundle for that!

Page 12: Symfony War Stories

Learning your stuff

http://www.sxc.hu/photo/1095604

Page 13: Symfony War Stories

Have you ever used?

● Event listeners and subscribers

● Form data transformers

● Twig extensions

● Profiler extensions

● DIC compiler passes

● more...

Page 14: Symfony War Stories

It's easy!

let's see few examples...

Page 15: Symfony War Stories

Event listeners and subscribers (Doctrine)

services: sensio.listener.search_indexer: class: Sensio\Listener\SearchIndexer tags: - name: doctrine.event_listener event: postPersist

Page 16: Symfony War Stories

namespace Sensio\Listener;

use Doctrine\ORM\Event\LifecycleEventArgs;use Sensio\Entity\Product;

class SearchIndexer{ public function postPersist(LifecycleEventArgs $args) { $entity = $args->getEntity(); $entityManager = $args->getEntityManager();

if ($entity instanceof Product) { /* Index me */ } }}

Page 17: Symfony War Stories

Lifecycle callbacks (Doctrine)

/** * @ORM\Entity() * @ORM\HasLifecycleCallbacks() */class User{ /** * @ORM\PrePersist */ public function updateCreatedAt() { /* ... */ }}

Page 18: Symfony War Stories

Event listeners and subscribers (Symfony)

services: sensio.action_listener: class: Sensio\MyBundle\EventListener\MyListener tags: - name: kernel.event_listener event: kernel.controller method: onKernelController

Page 19: Symfony War Stories

namespace Sensio\MyBundle\EventListener;

class MyListener{ public function onKernelController( FilterControllerEvent $event) { $controller = $event->getController(); $request = $event->getRequest();

// ... }}

Page 20: Symfony War Stories

Event listeners and subscribers (Forms)

$callback = function(FormEvent $event) { if (null === $event->getData()) { $formData = $event->getForm()->getData(); $event->setData($formData); }};

$builder->add('email', 'text');$builder->get('email') ->addEventListener( FormEvents::PRE_BIND, $callback );

Page 21: Symfony War Stories

Data transformers (Forms)

class IssueToNumberTransformer implements DataTransformerInterface { public function transform($issue) { // return issue number }

public function reverseTransform($number) { // return Issue instance }}

Page 22: Symfony War Stories

$field = $builder->create('issue', 'text') ->addModelTransformer(new IssueToNumberTransformer());

$builder->add($field);

Page 23: Symfony War Stories

Twig extensions

<!-- Instead of: -->

<div class="price"> ${{ 9800.333|number_format(2, '.', ',') }}</div>

<!-- just do: -->

<div class="price"> {{ 9800.333|price }}</div>

Page 24: Symfony War Stories

class SensioExtension extends \Twig_Extension{ public function getFilters() { return array( 'price' => new \Twig_Filter_Method( $this, 'priceFilter') ); }

public function getName() { return 'sensio_extension'; }

public function priceFilter($number, /* ... */ ) {}}

Page 25: Symfony War Stories

public function priceFilter( $number, $decimals = 0, $decPoint = '.', $sep = ','){ $price = number_format( $number, $decimals, $decPoint, $sep );

return '$'.$price;}

Page 26: Symfony War Stories

services: sensio.twig.acme_extension: class: Sensio\Twig\SensioExtension tags: - { name: twig.extension }

Page 27: Symfony War Stories

Web profiler

Page 28: Symfony War Stories

./app/console container:debug

./app/console container:debug twig.loader

./app/console router:debug

./app/console router:debug homepage

./app/console router:match /logout

Debugging commands

Page 29: Symfony War Stories

Debugging commands

Page 30: Symfony War Stories

Keeping your playground clean

http://www.rgbstock.com/bigphoto/mZTKnw6

Page 31: Symfony War Stories

Use the service container!

Page 32: Symfony War Stories

public function publishAction($date){ $show = $this->findShow($date); $fileName = sprintf('show-%s.json', $date->format('Y-m-d'));

while (file_exists($fileName)) { $fileName = $fileName.preg_replace('/.json$/', '-1.json'); }

$options = array( /* options here */ ); $s3 = new AmazonS3($options);

$objectOptions = array( 'body' => json_encode($show), 'acl' => $options['objectAcl']);

if (!$s3->create_object('my-bucket', $fileName, $objectOptions) { throw new \Exception('Could not save file'); }

// ...}

Page 33: Symfony War Stories

public function publishAction($date){ $show = $this->findShow($date);

$fileNameResolver = new FileNameResolver(); $filesystem = $this->get('gafrette_filesystem');

$publisher = new Publisher( $fileNameResolver, $filesystem );

$publisher->publish($show, $date);}

Page 34: Symfony War Stories

Use the service container!

public function publishAction($date){ $show = $this->findShow($date); $publisher = $this->get('sensio.publisher'); $publisher->publish($show, $date);}

Page 35: Symfony War Stories

Be SOLID!

Page 36: Symfony War Stories

/** * @ORM\Entity() */class Product{ // ...

public function createOrderReport($month) { // $this->em->getRepository() ... }

public function setEntityManager($em) { $this->em = $em; }}

Page 37: Symfony War Stories

class OrderReportGenerator{ private $em = null;

public function __construct(EntityManager $em) { $this->em = $em; }

public function generate(Product $product, $month) { // ... }}

Page 38: Symfony War Stories

Building quality in

http://www.rgbstock.com/photo/nrcyovQ/perfect

Page 39: Symfony War Stories

Unit tests

class ReportTest extends \PHPUnit_Framework_TestCase{ public function testThatItReturnsFilePath() { $report = new Report();

$file = $report->create('January');

$this->assertSame('/january.csv', $file); }}

Page 40: Symfony War Stories

... or specs

namespace spec;

class Report extends \PHPSpec2\ObjectBehavior{ function it_returns_file_path() { $this->create('January') ->shouldReturn('/january.csv'); }}

Page 41: Symfony War Stories

Managing expectations

Feature: Viewing recent news on the homepage As a Marketing Manager I want Visitors to see recent news on the homepage In order to get them interested in the content

Scenario: Viewing recent news Given there are 10 news items And there were 5 news items written since yesterday When I visit the homepage Then I should see 5 recent news items in the news section

Scenario: There is not enough news Given there are 10 news items But there were 3 news items written since yesterday When I visit the homepage Then I should see 3 recent news items in the news section

Page 42: Symfony War Stories

Thank you!