Slide 1

Slide 1 text

SensioLabs Get ready for Symfony 4

Slide 2

Slide 2 text

Christian Flothmann Symfony Core Team & Documentation Team work at SensioLabs Germany github.com/xabbuh @xabbuh

Slide 3

Slide 3 text

The Symfony Release Cycle

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

• one patch release a month • minor releases twice a year • new major releases every two years • N.4 at the same time as (N+1).0 • N.4 is an LTS release The Symfony Release Cycle http://symfony.com/roadmap

Slide 6

Slide 6 text

Symfony 3.3

Slide 7

Slide 7 text

Workflow

Slide 8

Slide 8 text

• new Twig function: workflow_has_place() • new Event: workflow.entered Workflow

Slide 9

Slide 9 text

Dotenv

Slide 10

Slide 10 text

• new component • reads .env files • makes them available through getenv(), $_SERVER, and $_ENV Dotenv

Slide 11

Slide 11 text

An example .env file # Database credentials DB_USER=root DB_PASS=pass # the DB password

Slide 12

Slide 12 text

Loading a .env file $loader = require __DIR__.'/../app/autoload.php'; use Symfony\Component\Dotenv\Dotenv; if (file_exists(__DIR__.'/../.env')) { $dotenv = new Dotenv(); $dotenv->load(__DIR__.'/../.env'); } Debug::enable(); $kernel = new AppKernel('dev', true); $request = Request::createFromGlobals(); $response = $kernel->handle($request); $response->send(); $kernel->terminate($request, $response);

Slide 13

Slide 13 text

Cache

Slide 14

Slide 14 text

• compatible with PSR-16 o simple caching Layer o support to convert PSR-16 caches to PSR-6 adapters and vice versa • Memcached Support Cache

Slide 15

Slide 15 text

Cache – PSR-6 interface CacheItemInterface { public function getKey(); public function get(); public function isHit(); public function set($value); public function expiresAt($expiration); public function expiresAfter($time); }

Slide 16

Slide 16 text

Cache – PSR-6 interface CacheItemPoolInterface { public function getItem($key); public function getItems(array $keys = array()); public function hasItem($key); public function clear(); public function deleteItem($key); public function deleteItems(array $keys); public function save(CacheItemInterface $item); public function saveDeferred(CacheItemInterface $item); public function commit(); }

Slide 17

Slide 17 text

Cache – PSR-16 interface CacheInterface { public function get($key, $default = null); public function set($key, $value, $ttl = null); public function delete($key); public function clear(); public function getMultiple($keys, $default = null); public function setMultiple($values, $ttl = null); public function deleteMultiple($keys); public function has($key); }

Slide 18

Slide 18 text

Cache – Using PSR-16 Caches use Symfony\Component\Cache\Simple\FilesystemCache; $cache = new FilesystemCache(); $cache->set('stats.num_products', 4711, 3600); if (!$cache->has('stats.num_products')) { // ... item does not exists in the cache } $numProducts = $cache->get( 'stats.num_products‘, 100 ); $cache->delete('stats.num_products'); $cache->clear();

Slide 19

Slide 19 text

Cache – PSR-16 to PSR-6 use Symfony\Component\Cache\Simple\FilesystemCache; use Symfony\Component\Cache\Adapter\SimpleCacheAdapter; $psr16Cache = new FilesystemCache(); $psr6Cache = new SimpleCacheAdapter($psr16Cache);

Slide 20

Slide 20 text

Cache – PSR-6 to PSR-16 use Symfony\Component\Cache\Adapter\FilesystemAdapter; use Symfony\Component\Cache\Simple\Psr6Cache; $psr6Cache = new FilesystemAdapter(); $psr16Cache = new Psr6Cache($psr6Cache);

Slide 21

Slide 21 text

DependencyInjection

Slide 22

Slide 22 text

Importing config files in Symfony 3.2 imports: - { resource: parameters.yml } - { resource: security.yml } - { resource: services.yml } - { resource: admin/ }

Slide 23

Slide 23 text

Importing config files using glob patterns imports: - { resource: "*.yml" } - { resource: "common/**/*.xml" } - { resource: "/etc/myapp/*.{yml,xml}" } - { resource: "bundles/*/{xml,yaml}/services.{yml,xml}" } Support for double star (**) in glob patterns is part of the Finder component in 3.3.

Slide 24

Slide 24 text

• class is optional, falls back to id • support for default values per file • inheritance of tags from parent definition Configuration improvements

Slide 25

Slide 25 text

Verbose config before Symfony 3.3 services: app.voter: abstract: true autowire: true public: false app.category_voter: class: AppBundle\Security\CategoryVoter parent: app.voter tags: [ { name: security.voter } ] app.comment_voter: class: AppBundle\Security\CommentVoter parent: app.voter tags: [ { name: security.voter } ] app.post_voter: class: AppBundle\Security\PostVoter parent: app.voter tags: [ { name: security.voter } ]

Slide 26

Slide 26 text

Shortened config with Symfony 3.3 services: _defaults: autowire: true public: false tags: - name: security.voter AppBundle\Security\CategoryVoter: ~ AppBundle\Security\CommentVoter: ~ AppBundle\Security\PostVoter: ~

Slide 27

Slide 27 text

Inheriting tags in Symfony 3.3 services: _defaults: autowire: true public: false inherit_tags: true app.voter: abstract: true tags: [ { name: security.voter } ] AppBundle\Security\CategoryVoter: parent: app.voter AppBundle\Security\CommentVoter: parent: app.voter AppBundle\Security\PostVoter: parent: app.voter AppBundle\Security\UserProvider: inherit_tags: false

Slide 28

Slide 28 text

Factory methods before Symfony 3.3 services: app.mailer: class: AppBundle\Mailer factory: - AppBundle\Mailer - getDefaultMailer

Slide 29

Slide 29 text

Omitting the factory method services: app.mailer: class: AppBundle\Mailer factory: - ~ - getDefaultMailer

Slide 30

Slide 30 text

Experimental Features

Slide 31

Slide 31 text

No content

Slide 32

Slide 32 text

DependencyInjection

Slide 33

Slide 33 text

Simplifying the voter example services: _defaults: autowire: true public: false tags: - name: security.voter AppBundle\Security\CategoryVoter: ~ AppBundle\Security\CommentVoter: ~ AppBundle\Security\PostVoter: ~

Slide 34

Slide 34 text

Using PSR-4 based discovery # app/config/services.yml services: AppBundle\Security\: resource: ../../src/AppBundle/Security autowire: true public: false tags: - name: security.voter

Slide 35

Slide 35 text

Getter injection abstract class NewsletterManager { abstract protected function getMailer(): MailerInterface; protected function getLogger(): LoggerInterface { return new NullLogger(); } // ... }

Slide 36

Slide 36 text

Getter injection services: app.newsletter_manager: class: AppBundle\Mail\NewsletterManager getters: getMailer: '@mailer' getLogger: '@logger'

Slide 37

Slide 37 text

Getter autowiring services: app.newsletter_manager: class: AppBundle\Mail\NewsletterManager autowire: ['get*'] AppBundle\Mailer: ~ MailerInterface: '@AppBundle\Mailer'

Slide 38

Slide 38 text

Inheriting tags in Symfony 3.3 services: _defaults: autowire: true public: false inherit_tags: true app.voter: abstract: true tags: [ { name: security.voter } ] AppBundle\Security\CategoryVoter: parent: app.voter AppBundle\Security\CommentVoter: parent: app.voter AppBundle\Security\PostVoter: parent: app.voter AppBundle\Security\UserProvider: inherit_tags: false

Slide 39

Slide 39 text

Interface based attribute configuration services: _defaults: autowire: true public: false _instanceof: Symfony\Component\Security\Core\Authorization\Voter\Voter: tags: [ { name: security.voter } ] AppBundle\Security\CategoryVoter: ~ AppBundle\Security\CommentVoter: ~ AppBundle\Security\PostVoter: ~ AppBundle\Security\UserProvider: ~

Slide 40

Slide 40 text

Symfony 4.0

Slide 41

Slide 41 text

ClassLoader

Slide 42

Slide 42 text

• component is to be removed • use Composer instead • (or any other PSR-4 compatible autoloader package) ClassLoader

Slide 43

Slide 43 text

DependencyInjection

Slide 44

Slide 44 text

• service identifiers are case sensitive • invalid options (YAML format) lead to exceptions • private services are not accessible through Container::has() or Container::get(), inject them if needed DependencyInjection

Slide 45

Slide 45 text

DefinitionDecorator is deprecated $mailer = $container->register('mailer', 'Mailer'); $mailer->setAbstract(true); $smtpMailer = new DefinitionDecorator('mailer'); $smtpMailer->setArguments([ 'username' => 'foo', 'password' => 'bar', ]); $container->setDefinition('mailer1', $smtpMailer);

Slide 46

Slide 46 text

Use ChildDefinition instead $mailer = $container->register('mailer', 'Mailer'); $mailer->setAbstract(true); $smtpMailer = new ChildDefinition ('mailer'); $smtpMailer->setArguments([ 'username' => 'foo', 'password' => 'bar', ]); $container->setDefinition('mailer1', $smtpMailer);

Slide 47

Slide 47 text

Form

Slide 48

Slide 48 text

• choices_as_values option removed • part of BC layer of Symfony 2.7 • deprecated since Symfony 3.1 ChoiceType

Slide 49

Slide 49 text

• dropped support to pass callables as strings to choice_value/choice_label ChoiceType

Slide 50

Slide 50 text

Callable as string, before Symfony 4 public function buildForm( FormBuilderInterface $builder, array $options ) { $builder->add( 'categories', ChoiceType::class, [ 'choice_label' => 'strtolower', ] ); }

Slide 51

Slide 51 text

Callables in Symfony 4 public function buildForm( FormBuilderInterface $builder, array $options ) { $builder->add( 'categories', ChoiceType::class, [ 'choice_label' => function ($choice) { return strtolower($choice); }, ] ); }

Slide 52

Slide 52 text

• isValid() cannot be called for not submitted forms Form

Slide 53

Slide 53 text

Before Symfony 4 $form = $this->createForm( UserType::class, $user ); $form->handleRequest($request); if ($form->isValid()) { // do something with // the submitted data }

Slide 54

Slide 54 text

Symfony 4 $form = $this->createForm( UserType::class, $user ); $form->handleRequest($request); if ( $form->isSubmitted() && $form->isValid() ) { // do something with // the submitted data }

Slide 55

Slide 55 text

HttpFoundation

Slide 56

Slide 56 text

• lots of methods are final • don‘t override them in custom response classes Response

Slide 57

Slide 57 text

• isMethodSafe() doesn‘t check for cacheable methods • HEAD and GET are cacheable • OPTIONS and TRACE are safe too Request

Slide 58

Slide 58 text

Cacheable methods check before 4.0 if ( $request->isMethodSafe() ) { // true for GET, HEAD }

Slide 59

Slide 59 text

Cacheable methods check with Symfony 4 if ( $request->isMethodCacheable() ) { // true for GET, HEAD }

Slide 60

Slide 60 text

Check for safe methods // note: true necessary only for // BC in Symfony 3.x if ( $request->isMethodSafe(true) ) { // true for GET, HEAD, // OPTIONS, and TRACE }

Slide 61

Slide 61 text

Security

Slide 62

Slide 62 text

• RoleInterface removed • use strings for roles • not recommend: extending the Role class o Role class likely to be removed too Security

Slide 63

Slide 63 text

Validator

Slide 64

Slide 64 text

• base class for validator tests located in Symfony\Component\Validator\Test (not Tests) AbstractConstraintValidatorTest

Slide 65

Slide 65 text

strict option defaults to true /** * @Assert\Choice( * choices = { * "male", "female“ * }, * strict = true * ) */

Slide 66

Slide 66 text

Yaml

Slide 67

Slide 67 text

• mapping keys must be unique • colons separating keys and values need a following space • strings starting with % must be quoted Parser changes

Slide 68

Slide 68 text

Valid YAML file before Symfony 4 foo: { bar:baz, a: b } foo: baz bar: %foobar

Slide 69

Slide 69 text

Valid YAML file with Symfony 4 foo: { bar: baz, a: b } bar: '%foobar'

Slide 70

Slide 70 text

• dropped boolean arguments of Yaml::parse() • dropped boolean arguments of Yaml::dump() • use flags instead API changes

Slide 71

Slide 71 text

Parsing/dumping before Yaml::parse( '{ "foo": "bar", "foobar": "baz" }', true, true, true ); Yaml::dump( array('foo' => new A(), 'bar' => 1), 2, 4, true, true );

Slide 72

Slide 72 text

Parsing/dumping with Symfony 4 Yaml::parse( '{ "foo": "bar", "foobar": "baz" }', Yaml::PARSE_EXCEPTION_ON_INVALID_TYPE | Yaml::PARSE_OBJECT | Yaml::PARSE_OBJECT_FOR_MAP ); Yaml::dump( array('foo' => new A(), 'bar' => 1), 2, 4, Yaml::DUMP_EXCEPTION_ON_INVALID_TYPE | Yaml::DUMP_OBJECT );

Slide 73

Slide 73 text

SensioLabs Thank you!