SlideShare una empresa de Scribd logo
1 de 88
Descargar para leer sin conexión
Symfony 4
Workshop
Victoria Quirante - @vicqr
Nacho Martin - @nacmartin
Notes: http://symfony4.limenius.com/
Nacho Martín
@nacmartin
nacho@limenius.com
Victoria Quirante
@vicqr
victoria@limenius.com
We build tailor-made projects with Symfony and React
We have been working with Symfony since 2008
We provide development, consulting and training
Symfony 4
We are here
Symfony Evolution
Symfony 12005 A monolith (very different)
Symfony 22011 Components appear
Components used in popular projects
Doctrine
Silex
Laravel
Symfony Evolution
Symfony 12005 A monolith (very different)
Symfony 22011 Components appear
Symfony 32015 Brief intermediate step
Symfony 42017 Compose your apps
Symfony 2/3
SF 2
Web app
SF 2
API
SF 2
Microservice
SF 4
Web app
SF4
API
SF4
Microservice
Symfony 4
Symfony 4
SF4 SF 4
Web app
SF4
API
SF4
Microservice
We need something to smooth
out these transformations
Symfony Flex
Symfony Flex is a tool to implement
Symfony 4 philosophy
It is a composer plugin that comes with
Symfony 4
The idea is automation to the max
when installing and configuring packages
Modifies the behaviour of the
require and update commands
Allows Symfony to perform tasks before
or after the composer commands
Symfony 4
Your application
with Symfony Flex
composer req mailer
Symfony Flex
Server
Recipe?
No
Regular install
With composer
Symfony 4
Your application
with Symfony Flex
composer req mailer
Symfony Flex
Server
Recipe?
Yes
Install them
With composer
Follow recipe instructions
Decide which packages to install
Run any task to configure them
http://symfony.sh
Directory Structure
my-project/
├── config/
│   ├── bundles.php
│   ├── packages/
│   ├── routes.yaml
│   └── services.yaml
├── public/
│   └── index.php
├── src/
│   ├── ...
│   └── Kernel.php
├── templates/
└── vendor/
Doctrine
Entity
Entity
namespace AppEntity;
class Movie
{
private $id;
private $name;
private $director;
private $year;
private $picture;
}
Entity /**
* @ORMEntity()
* @ORMTable(name="movie")
*/
class Movie
{
/**
* @ORMColumn(type="integer")
* @ORMId
* @ORMGeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @ORMColumn(type="string")
*/
private $name;
/**
* @ORMColumn(type="string", length=100)
*/
private $director;
/**
* @ORMColumn(type="smallint")
*/
private $year;
/**
* @ORMColumn(type="string")
*/
private $picture;
}
Entity
Code that has to do with the model itself.
Doesn’t depend on services, or query the DB.
Accessors
In this workshop we are going to use setters and getters:
•getDirector()
•setDirector()
This is not the only way. See for instance:
http://williamdurand.fr/2013/08/07/ddd-with-symfony2-folder-structure-and-code-first/
Entity Manager
Entity Manager
$em = $this->getDoctrine()->getManager();
$em->getRepository(Movie::class)->find($movieId);
$em = $this->getDoctrine()->getManager();
$em->persist($sale);
$em->flush();
Doctrine Query Language (DQL)
$em = $this->getDoctrine()->getManager();
$query = $em->createQuery(
'SELECT m, a FROM App:Movie m LEFT JOIN m.actors a WHERE
m.id = :id'
)->setParameter('id', $movieId);
$movie = $query->getOneOrNullResult();
Query Builder
$em = $this->getDoctrine()->getManager();
$query = $em->getRepository(Movie::class)
->createQueryBuilder('m')
->select('m, a')
->leftJoin('m.actors', 'a')
->where('m.id = :id')
->setParameter('id', $movieId)
->getQuery();
$movie = $query->getOneOrNullResult();
Entity Manager
Code that deals with retrieving or persisting
entities.
Fixtures

With Alice
We could do this
for ($i = 0; $i < 10; $i ++) {
$movie = new Movie();
$movie->setYear(1994);
$movie->setName('Pulp Fiction'.$i);
//...
$em->persist($movie);
}
$em->flush();
With Alice
AppEntityMovie:
movie{1..10}:
name: '<sentence(4, true)>'
director: '<name()>'
year: '<numberBetween(1970, 2017)>'
picture: '<image("./public/images", 500, 500, "cats", false)>'
See all the generators in
https://github.com/fzaninotto/Faker
Relationships
appentitymovie:
actor{1..10}:
#…
movie{1..10}:
#...
actors: ["@actor<numberBetween(1, 3)>", "@actor<numberBetween(4, 6)>"]
Twig
Twig
{{ }}
{% %}
Display Data
Define Structures
Access variables
{{ foo }}
{{ foo.bar }}
{{ foo['bar'] }}
- Checks if foo is an array and bar an element
- If not, checks if foo is an object and bar a property
- If not, checks if foo is an object and bar a method
- If not, checks if foo is an object and getBar a method
- If not, checks if foo is an object and isBar a method
{{ foo.bar }}
Access variables
{% for user in users %}
{{ user.username }}
{% endfor %}
For each
{% for i in 0..10 %}
{{ i }}
{% endfor %}
For
For … else
{% for item in items %}
{{ item }}
{% else %}
No items.
{% endfor %}
<html><head>...</head>
<body>
<h1>
{% block title %}{% endblock %}
</h1>
{% block body %}{% endblock %}
</body></html>
Template inheritance
templates/layout.html.twig
{% extends "layout.twig" %}
{% block title %}
Home
{% endblock %}
{% block body %}
Lorem ipsum...
{% endblock %}
Template inheritance
templates/home.html.twig
{% extends "layout.twig" %}
{% block title %}
Movie list
{% endblock %}
{% block body %}
Duis aute irure dolor in..
{% endblock %}
Template inheritance
templates/movies.html.twig
Webpack

Encore
Webpack
Webpack
The standard nowadays.
Very powerful.
Steep learning curve.
Cons
Pros
Webpack Encore
A wrapper around Webpack that makes it
easier to set up.
It solves a big % of cases.
If you require something specific, you can still
use Webpack without Encore.
Forms
Create a form
$form = $this->createFormBuilder($task)
->add('task', TextType::class)
->add('dueDate', DateType::class)
->add('save', SubmitType::class, ['label' => 'Create Post'])
->getForm();
return $this->render('default/new.html.twig', [
'form' => $form->createView(),
]);
Forms in Twig
{{ form_start(form) }}
{{ form_widget(form) }}
{{ form_end(form) }}
You can customise a lot the rendering of every widget,
If you need to.
Handle submission
$form = $this->createFormBuilder($task)
->add('task', TextType::class)
->add('dueDate', DateType::class)
->add('save', SubmitType::class, ['label' => 'Create Task'])
->getForm();
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($task);
$em->flush();
return $this->redirectToRoute('task_success');
}
return $this->render('default/new.html.twig', [
'form' => $form->createView(),
]);
Forms in their own classes
class TaskType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('task')
->add('dueDate', null, array('widget' => 'single_text'))
->add('save', SubmitType::class);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => Task::class,
));
}
}
Events
Event and EventListener
Event EventListener
dispatch
Event
class SaleEvent extends Event
{
const NAME = 'sale.created';
protected $sale;
protected $movie;
protected $numTickets;
public function __construct(Sale $sale, Movie $movie, int $numTickets)
{
$this->sale = $sale;
$this->movie = $movie;
$this->numTickets = $numTickets;
}
public function getSale()
{
return $this->sale;
}
public function getMovie()
{
return $this->movie;
}
public function getNumTickets()
{
return $this->numTickets;
}
}
A bag of parameters
that describe the event
Dispatch Events
$this->get('event_dispatcher')
->dispatch(
SaleEvent::NAME,
new SaleEvent($sale, $movie, $numTickets)
);
EventListener
Processes the event
class SaleListener
{
public function __construct(EntityManager $em)
{
$this->em = $em;
}
public function onSaleCreated(SaleEvent $event)
{
for ($i = 0; $i < $event->getNumTickets(); $i++) {
$ticket = new Ticket();
$ticket->setMovie($event->getMovie());
$ticket->setSale($event->getSale());
$ticket->setRow(1);
$ticket->setSeat(1);
$this->em->persist($ticket);
}
}
}
Services
Services
A service is an object that does something:
• Generate a thumbnail.
• Generate a PDF.
• A query to ElasticSearch.
• Log something.
• Send an email.
Example
class SaleLogger
{
private $logger;
public function __construct(LoggerInterface $logger)
{
$this->logger = $logger;
}
public function log(Sale $sale)
{
$this->logger->info('Sold ' . count($sale->getTickets()) . ' tickets to ' . $sale->getFullName());
}
}
Where does this come from?
Using services
public function listAction(SaleLogger $saleLogger)
{
//…
$saleLogger->log($sale);
}
Is injected with dependencies
Explicit configuration
# app/config/services.yml
services:
# explicitly configure the service
AppLoggerSaleLogger:
arguments:
$logger: '@monolog.logger.request'
Tagged services
$taggedServices = $container->findTaggedServiceIds(‘app.my_tag’);
foreach ($taggedServices as $id => $tags) {
$definition->addMethodCall('callAMethod', array(new Reference($id)));
}
AppMyServices:
resource: '../src/MyServices'
tags: ['app.my_tag']
Validation
Built in assertions
/**
* @ORMColumn(type="string")
* @AssertLength(min=2)
*/
private $fullName;
/**
* @ORMColumn(type="string")
* @AssertEmail()
*/
private $email;
/**
* @ORMColumn(type="text")
* @AssertLength(max=100)
*/
private $question;
Built in assertions
There are 47 assertions
From NotNull to Isbn
And we can write our
own assertions
Use validators
if ($form->isValid()) {}
$author = new Author();
$validator = $this->get('validator');
$errors = $validator->validate($author);
Dependency container
Standalone use
$email = ‘obama@usa.gov’;
$emailConstraint = new AssertEmail();
$emailConstraint->message = 'Invalid email address';
$errorList = $this->get('validator')->validate(
$email,
$emailConstraint
);
Creating new constraints
Constraint Validator
Validate
Constraint
class HasAvailableSeats extends Constraint
{
public $message = 'No {{ number }} available seats’;
protected $movie;
public function __construct($options)
{
$this->movie = $options['movie'];
}
public function getMovie()
{
return $this->movie;
}
public function validatedBy()
{
return get_class($this).'Validator';
}
}
No logic,
data that describes
the constraint
Who validates this?
class HasAvailableSeatsValidator extends ConstraintValidator
{
public function validate($value, Constraint $constraint)
{
$available = $constraint->getMovie()->getAvailableSeats();
if ($value > $available) {
$this->context->buildViolation($constraint->message)
->setParameter('{{ number }}', $value)
->addViolation();
}
}
}
Validator
Validation logic
APIs
Up to level 2
Good use of HTTP verbs (GET, POST, PUT, DELETE, PATCH…)
Structure based on resources (/movies, /movies/31).
Use of HTTP Status codes (200, 201, 406, …).
Use of representations (JSON, XML, …).
Serializer: the idea
$recipe = new Recipe();
$recipe->setName($content['name']);
$recipe->setEnergy($content['energy']);
$recipe->setServings($content['servings']);
Request->Our object (manual deserialization)
$responseData = [
   'id' => $recipe->getId(),
   'name' => $recipe->getName(),
   'energy' => $recipe->getEnergy(),
   'servings' => $recipe->getServings(),
   ];
$response = new JsonResponse($responseData, 201);
Our object->Request (manual serialization)
Tedious!
$response = new Response($serializer->serialize($recipe, 'json'), 201);
$responseData = [
   'id' => $recipe->getId(),
   'name' => $recipe->getName(),
   'energy' => $recipe->getEnergy(),
   'servings' => $recipe->getServings(),
   ];
$response = new JsonResponse($responseData, 201);
Our object->Request (manual serialization)
Serialize
$recipe = $serializer->deserialize($content, Recipe::class, 'json');
$recipe = new Recipe();
$recipe->setName($content['name']);
$recipe->setEnergy($content['energy']);
$recipe->setServings($content['servings']);
Request->Our object (manual deserialization)
Deserialize
Serializer
Representation in API != DB
{
id: 9,
name: "victoriaq",
password: "encryptedPassword",
email: "victoria@limenius.com",
avatar: "avatar.jpg",
twitter_handler: "vicqr",
profile: {
id: 19,
bio: "My bio."
}
}
I want this to be “username”
I don’t want to expose it!
Only in profile, not in list
We want to prepend “thumb_”
Only in version 2 of the API
I’d like this to be bio:”My bio”
We do this in the normalizer
Annotations
MaxDepth
• Detect and limit the serialization depth
• Especially useful when serializing large trees
Groups
• Sometimes, you want to serialize different sets of attributes from your entities
• Groups are a handy way to achieve this need
API Platform makes it very easy
Admin Panel
Admin on REST with API Platform
Sonata Admin
Easy Admin
Thanks! @nacmartin
nacho@limenius.com
@vicqr
victoria@limenius.com

Más contenido relacionado

La actualidad más candente

Your Business. Your Language. Your Code - dpc13
Your Business. Your Language. Your Code - dpc13Your Business. Your Language. Your Code - dpc13
Your Business. Your Language. Your Code - dpc13
Stephan Hochdörfer
 
Beijing Perl Workshop 2008 Hiveminder Secret Sauce
Beijing Perl Workshop 2008 Hiveminder Secret SauceBeijing Perl Workshop 2008 Hiveminder Secret Sauce
Beijing Perl Workshop 2008 Hiveminder Secret Sauce
Jesse Vincent
 

La actualidad más candente (19)

Your Business. Your Language. Your Code - dpc13
Your Business. Your Language. Your Code - dpc13Your Business. Your Language. Your Code - dpc13
Your Business. Your Language. Your Code - dpc13
 
Non Conventional Android Programming En
Non Conventional Android Programming EnNon Conventional Android Programming En
Non Conventional Android Programming En
 
A Phing fairy tale - ConFoo13
A Phing fairy tale - ConFoo13A Phing fairy tale - ConFoo13
A Phing fairy tale - ConFoo13
 
Crafting Quality PHP Applications (ConFoo YVR 2017)
Crafting Quality PHP Applications (ConFoo YVR 2017)Crafting Quality PHP Applications (ConFoo YVR 2017)
Crafting Quality PHP Applications (ConFoo YVR 2017)
 
Kicking off with Zend Expressive and Doctrine ORM (ConFoo YVR 2017)
Kicking off with Zend Expressive and Doctrine ORM (ConFoo YVR 2017)Kicking off with Zend Expressive and Doctrine ORM (ConFoo YVR 2017)
Kicking off with Zend Expressive and Doctrine ORM (ConFoo YVR 2017)
 
Data Validation models
Data Validation modelsData Validation models
Data Validation models
 
Being Dangerous with Twig
Being Dangerous with TwigBeing Dangerous with Twig
Being Dangerous with Twig
 
Actions filters
Actions filtersActions filters
Actions filters
 
Testing API platform with Behat BDD tests
Testing API platform with Behat BDD testsTesting API platform with Behat BDD tests
Testing API platform with Behat BDD tests
 
Dip Your Toes in the Sea of Security (ConFoo YVR 2017)
Dip Your Toes in the Sea of Security (ConFoo YVR 2017)Dip Your Toes in the Sea of Security (ConFoo YVR 2017)
Dip Your Toes in the Sea of Security (ConFoo YVR 2017)
 
Getting big without getting fat, in perl
Getting big without getting fat, in perlGetting big without getting fat, in perl
Getting big without getting fat, in perl
 
Diving into HHVM Extensions (PHPNW Conference 2015)
Diving into HHVM Extensions (PHPNW Conference 2015)Diving into HHVM Extensions (PHPNW Conference 2015)
Diving into HHVM Extensions (PHPNW Conference 2015)
 
Solving Real World Problems with YUI 3: AutoComplete
Solving Real World Problems with YUI 3: AutoCompleteSolving Real World Problems with YUI 3: AutoComplete
Solving Real World Problems with YUI 3: AutoComplete
 
TWIG: the flexible, fast and secure template language for PHP
TWIG: the flexible, fast and secure template language for PHPTWIG: the flexible, fast and secure template language for PHP
TWIG: the flexible, fast and secure template language for PHP
 
PHP 5.3 in practice
PHP 5.3 in practicePHP 5.3 in practice
PHP 5.3 in practice
 
Keeping it small - Getting to know the Slim PHP micro framework
Keeping it small - Getting to know the Slim PHP micro frameworkKeeping it small - Getting to know the Slim PHP micro framework
Keeping it small - Getting to know the Slim PHP micro framework
 
Beijing Perl Workshop 2008 Hiveminder Secret Sauce
Beijing Perl Workshop 2008 Hiveminder Secret SauceBeijing Perl Workshop 2008 Hiveminder Secret Sauce
Beijing Perl Workshop 2008 Hiveminder Secret Sauce
 
Modern Web Development with Perl
Modern Web Development with PerlModern Web Development with Perl
Modern Web Development with Perl
 
CSS in React - Will Change Transform
CSS in React - Will Change TransformCSS in React - Will Change Transform
CSS in React - Will Change Transform
 

Similar a Symfony 4 Workshop - Limenius

The state of Symfony2 - SymfonyDay 2010
The state of Symfony2 - SymfonyDay 2010The state of Symfony2 - SymfonyDay 2010
The state of Symfony2 - SymfonyDay 2010
Fabien Potencier
 
Refactoring Simple Example
Refactoring Simple ExampleRefactoring Simple Example
Refactoring Simple Example
liufabin 66688
 
symfony on action - WebTech 207
symfony on action - WebTech 207symfony on action - WebTech 207
symfony on action - WebTech 207
patter
 
DDD on example of Symfony (Webcamp Odessa 2014)
DDD on example of Symfony (Webcamp Odessa 2014)DDD on example of Symfony (Webcamp Odessa 2014)
DDD on example of Symfony (Webcamp Odessa 2014)
Oleg Zinchenko
 

Similar a Symfony 4 Workshop - Limenius (20)

The state of Symfony2 - SymfonyDay 2010
The state of Symfony2 - SymfonyDay 2010The state of Symfony2 - SymfonyDay 2010
The state of Symfony2 - SymfonyDay 2010
 
Unittests für Dummies
Unittests für DummiesUnittests für Dummies
Unittests für Dummies
 
Meet Magento DE 2016 - Kristof Ringleff - Growing up with Magento
Meet Magento DE 2016 - Kristof Ringleff - Growing up with MagentoMeet Magento DE 2016 - Kristof Ringleff - Growing up with Magento
Meet Magento DE 2016 - Kristof Ringleff - Growing up with Magento
 
Things to consider for testable Code
Things to consider for testable CodeThings to consider for testable Code
Things to consider for testable Code
 
Symfony War Stories
Symfony War StoriesSymfony War Stories
Symfony War Stories
 
Refactoring Simple Example
Refactoring Simple ExampleRefactoring Simple Example
Refactoring Simple Example
 
Growing up with Magento
Growing up with MagentoGrowing up with Magento
Growing up with Magento
 
"Full Stack frameworks or a story about how to reconcile Front (good) and Bac...
"Full Stack frameworks or a story about how to reconcile Front (good) and Bac..."Full Stack frameworks or a story about how to reconcile Front (good) and Bac...
"Full Stack frameworks or a story about how to reconcile Front (good) and Bac...
 
symfony on action - WebTech 207
symfony on action - WebTech 207symfony on action - WebTech 207
symfony on action - WebTech 207
 
Zend server 6 using zf2, 2013 webinar
Zend server 6 using zf2, 2013 webinarZend server 6 using zf2, 2013 webinar
Zend server 6 using zf2, 2013 webinar
 
Writing JavaScript that doesn't suck
Writing JavaScript that doesn't suckWriting JavaScript that doesn't suck
Writing JavaScript that doesn't suck
 
New Symfony Tips & Tricks (SymfonyCon Paris 2015)
New Symfony Tips & Tricks (SymfonyCon Paris 2015)New Symfony Tips & Tricks (SymfonyCon Paris 2015)
New Symfony Tips & Tricks (SymfonyCon Paris 2015)
 
Event Sourcing with php
Event Sourcing with phpEvent Sourcing with php
Event Sourcing with php
 
Symfony2 - OSIDays 2010
Symfony2 - OSIDays 2010Symfony2 - OSIDays 2010
Symfony2 - OSIDays 2010
 
Javascript Memory leaks and Performance & Angular
Javascript Memory leaks and Performance & AngularJavascript Memory leaks and Performance & Angular
Javascript Memory leaks and Performance & Angular
 
Symfony tips and tricks
Symfony tips and tricksSymfony tips and tricks
Symfony tips and tricks
 
DDD on example of Symfony (Webcamp Odessa 2014)
DDD on example of Symfony (Webcamp Odessa 2014)DDD on example of Symfony (Webcamp Odessa 2014)
DDD on example of Symfony (Webcamp Odessa 2014)
 
Clean Javascript
Clean JavascriptClean Javascript
Clean Javascript
 
Migrare da symfony 1 a Symfony2
 Migrare da symfony 1 a Symfony2  Migrare da symfony 1 a Symfony2
Migrare da symfony 1 a Symfony2
 
Symfony2 - WebExpo 2010
Symfony2 - WebExpo 2010Symfony2 - WebExpo 2010
Symfony2 - WebExpo 2010
 

Más de Ignacio Martín

Symfony & Javascript. Combining the best of two worlds
Symfony & Javascript. Combining the best of two worldsSymfony & Javascript. Combining the best of two worlds
Symfony & Javascript. Combining the best of two worlds
Ignacio Martín
 

Más de Ignacio Martín (17)

Introduction to React Native Workshop
Introduction to React Native WorkshopIntroduction to React Native Workshop
Introduction to React Native Workshop
 
Server side rendering with React and Symfony
Server side rendering with React and SymfonyServer side rendering with React and Symfony
Server side rendering with React and Symfony
 
Server Side Rendering of JavaScript in PHP
Server Side Rendering of JavaScript in PHPServer Side Rendering of JavaScript in PHP
Server Side Rendering of JavaScript in PHP
 
Extending Redux in the Server Side
Extending Redux in the Server SideExtending Redux in the Server Side
Extending Redux in the Server Side
 
Redux Sagas - React Alicante
Redux Sagas - React AlicanteRedux Sagas - React Alicante
Redux Sagas - React Alicante
 
React Native Workshop - React Alicante
React Native Workshop - React AlicanteReact Native Workshop - React Alicante
React Native Workshop - React Alicante
 
Asegurando APIs en Symfony con JWT
Asegurando APIs en Symfony con JWTAsegurando APIs en Symfony con JWT
Asegurando APIs en Symfony con JWT
 
Redux saga: managing your side effects. Also: generators in es6
Redux saga: managing your side effects. Also: generators in es6Redux saga: managing your side effects. Also: generators in es6
Redux saga: managing your side effects. Also: generators in es6
 
Integrating React.js with PHP projects
Integrating React.js with PHP projectsIntegrating React.js with PHP projects
Integrating React.js with PHP projects
 
Introduction to Redux
Introduction to ReduxIntroduction to Redux
Introduction to Redux
 
Keeping the frontend under control with Symfony and Webpack
Keeping the frontend under control with Symfony and WebpackKeeping the frontend under control with Symfony and Webpack
Keeping the frontend under control with Symfony and Webpack
 
Integrando React.js en aplicaciones Symfony (deSymfony 2016)
Integrando React.js en aplicaciones Symfony (deSymfony 2016)Integrando React.js en aplicaciones Symfony (deSymfony 2016)
Integrando React.js en aplicaciones Symfony (deSymfony 2016)
 
Adding Realtime to your Projects
Adding Realtime to your ProjectsAdding Realtime to your Projects
Adding Realtime to your Projects
 
Symfony & Javascript. Combining the best of two worlds
Symfony & Javascript. Combining the best of two worldsSymfony & Javascript. Combining the best of two worlds
Symfony & Javascript. Combining the best of two worlds
 
Symfony 2 CMF
Symfony 2 CMFSymfony 2 CMF
Symfony 2 CMF
 
Doctrine2 sf2Vigo
Doctrine2 sf2VigoDoctrine2 sf2Vigo
Doctrine2 sf2Vigo
 
Presentacion git
Presentacion gitPresentacion git
Presentacion git
 

Último

Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Medical / Health Care (+971588192166) Mifepristone and Misoprostol tablets 200mg
 
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICECHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
9953056974 Low Rate Call Girls In Saket, Delhi NCR
 
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
masabamasaba
 
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
VictoriaMetrics
 
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
masabamasaba
 
The title is not connected to what is inside
The title is not connected to what is insideThe title is not connected to what is inside
The title is not connected to what is inside
shinachiaurasa2
 
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
masabamasaba
 

Último (20)

Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
 
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
 
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICECHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
 
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
 
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
 
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
 
AI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplateAI & Machine Learning Presentation Template
AI & Machine Learning Presentation Template
 
Announcing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK SoftwareAnnouncing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK Software
 
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
 
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
 
Architecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the pastArchitecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the past
 
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
 
WSO2CON 2024 - Does Open Source Still Matter?
WSO2CON 2024 - Does Open Source Still Matter?WSO2CON 2024 - Does Open Source Still Matter?
WSO2CON 2024 - Does Open Source Still Matter?
 
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
 
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
 
The title is not connected to what is inside
The title is not connected to what is insideThe title is not connected to what is inside
The title is not connected to what is inside
 
%in Soweto+277-882-255-28 abortion pills for sale in soweto
%in Soweto+277-882-255-28 abortion pills for sale in soweto%in Soweto+277-882-255-28 abortion pills for sale in soweto
%in Soweto+277-882-255-28 abortion pills for sale in soweto
 
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
 
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdfPayment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
 

Symfony 4 Workshop - Limenius

  • 1. Symfony 4 Workshop Victoria Quirante - @vicqr Nacho Martin - @nacmartin Notes: http://symfony4.limenius.com/
  • 2. Nacho Martín @nacmartin nacho@limenius.com Victoria Quirante @vicqr victoria@limenius.com We build tailor-made projects with Symfony and React We have been working with Symfony since 2008 We provide development, consulting and training
  • 5. Symfony Evolution Symfony 12005 A monolith (very different) Symfony 22011 Components appear
  • 6. Components used in popular projects
  • 10. Symfony Evolution Symfony 12005 A monolith (very different) Symfony 22011 Components appear Symfony 32015 Brief intermediate step Symfony 42017 Compose your apps
  • 11. Symfony 2/3 SF 2 Web app SF 2 API SF 2 Microservice SF 4 Web app SF4 API SF4 Microservice Symfony 4
  • 12. Symfony 4 SF4 SF 4 Web app SF4 API SF4 Microservice We need something to smooth out these transformations
  • 14. Symfony Flex is a tool to implement Symfony 4 philosophy
  • 15. It is a composer plugin that comes with Symfony 4 The idea is automation to the max when installing and configuring packages
  • 16. Modifies the behaviour of the require and update commands Allows Symfony to perform tasks before or after the composer commands
  • 17. Symfony 4 Your application with Symfony Flex composer req mailer Symfony Flex Server Recipe? No Regular install With composer
  • 18. Symfony 4 Your application with Symfony Flex composer req mailer Symfony Flex Server Recipe? Yes Install them With composer Follow recipe instructions Decide which packages to install Run any task to configure them
  • 20. Directory Structure my-project/ ├── config/ │   ├── bundles.php │   ├── packages/ │   ├── routes.yaml │   └── services.yaml ├── public/ │   └── index.php ├── src/ │   ├── ... │   └── Kernel.php ├── templates/ └── vendor/
  • 23. Entity namespace AppEntity; class Movie { private $id; private $name; private $director; private $year; private $picture; }
  • 24. Entity /** * @ORMEntity() * @ORMTable(name="movie") */ class Movie { /** * @ORMColumn(type="integer") * @ORMId * @ORMGeneratedValue(strategy="AUTO") */ private $id; /** * @ORMColumn(type="string") */ private $name; /** * @ORMColumn(type="string", length=100) */ private $director; /** * @ORMColumn(type="smallint") */ private $year; /** * @ORMColumn(type="string") */ private $picture; }
  • 25. Entity Code that has to do with the model itself. Doesn’t depend on services, or query the DB.
  • 26. Accessors In this workshop we are going to use setters and getters: •getDirector() •setDirector() This is not the only way. See for instance: http://williamdurand.fr/2013/08/07/ddd-with-symfony2-folder-structure-and-code-first/
  • 28. Entity Manager $em = $this->getDoctrine()->getManager(); $em->getRepository(Movie::class)->find($movieId); $em = $this->getDoctrine()->getManager(); $em->persist($sale); $em->flush();
  • 29. Doctrine Query Language (DQL) $em = $this->getDoctrine()->getManager(); $query = $em->createQuery( 'SELECT m, a FROM App:Movie m LEFT JOIN m.actors a WHERE m.id = :id' )->setParameter('id', $movieId); $movie = $query->getOneOrNullResult();
  • 30. Query Builder $em = $this->getDoctrine()->getManager(); $query = $em->getRepository(Movie::class) ->createQueryBuilder('m') ->select('m, a') ->leftJoin('m.actors', 'a') ->where('m.id = :id') ->setParameter('id', $movieId) ->getQuery(); $movie = $query->getOneOrNullResult();
  • 31. Entity Manager Code that deals with retrieving or persisting entities.
  • 33. We could do this for ($i = 0; $i < 10; $i ++) { $movie = new Movie(); $movie->setYear(1994); $movie->setName('Pulp Fiction'.$i); //... $em->persist($movie); } $em->flush();
  • 34. With Alice AppEntityMovie: movie{1..10}: name: '<sentence(4, true)>' director: '<name()>' year: '<numberBetween(1970, 2017)>' picture: '<image("./public/images", 500, 500, "cats", false)>' See all the generators in https://github.com/fzaninotto/Faker
  • 36. Twig
  • 37. Twig {{ }} {% %} Display Data Define Structures
  • 38. Access variables {{ foo }} {{ foo.bar }} {{ foo['bar'] }}
  • 39. - Checks if foo is an array and bar an element - If not, checks if foo is an object and bar a property - If not, checks if foo is an object and bar a method - If not, checks if foo is an object and getBar a method - If not, checks if foo is an object and isBar a method {{ foo.bar }} Access variables
  • 40. {% for user in users %} {{ user.username }} {% endfor %} For each
  • 41. {% for i in 0..10 %} {{ i }} {% endfor %} For
  • 42. For … else {% for item in items %} {{ item }} {% else %} No items. {% endfor %}
  • 43. <html><head>...</head> <body> <h1> {% block title %}{% endblock %} </h1> {% block body %}{% endblock %} </body></html> Template inheritance templates/layout.html.twig
  • 44. {% extends "layout.twig" %} {% block title %} Home {% endblock %} {% block body %} Lorem ipsum... {% endblock %} Template inheritance templates/home.html.twig
  • 45. {% extends "layout.twig" %} {% block title %} Movie list {% endblock %} {% block body %} Duis aute irure dolor in.. {% endblock %} Template inheritance templates/movies.html.twig
  • 48. Webpack The standard nowadays. Very powerful. Steep learning curve. Cons Pros
  • 49. Webpack Encore A wrapper around Webpack that makes it easier to set up. It solves a big % of cases. If you require something specific, you can still use Webpack without Encore.
  • 50. Forms
  • 51. Create a form $form = $this->createFormBuilder($task) ->add('task', TextType::class) ->add('dueDate', DateType::class) ->add('save', SubmitType::class, ['label' => 'Create Post']) ->getForm(); return $this->render('default/new.html.twig', [ 'form' => $form->createView(), ]);
  • 52. Forms in Twig {{ form_start(form) }} {{ form_widget(form) }} {{ form_end(form) }} You can customise a lot the rendering of every widget, If you need to.
  • 53. Handle submission $form = $this->createFormBuilder($task) ->add('task', TextType::class) ->add('dueDate', DateType::class) ->add('save', SubmitType::class, ['label' => 'Create Task']) ->getForm(); $form->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { $em = $this->getDoctrine()->getManager(); $em->persist($task); $em->flush(); return $this->redirectToRoute('task_success'); } return $this->render('default/new.html.twig', [ 'form' => $form->createView(), ]);
  • 54. Forms in their own classes class TaskType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) { $builder ->add('task') ->add('dueDate', null, array('widget' => 'single_text')) ->add('save', SubmitType::class); } public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults(array( 'data_class' => Task::class, )); } }
  • 56. Event and EventListener Event EventListener dispatch
  • 57. Event class SaleEvent extends Event { const NAME = 'sale.created'; protected $sale; protected $movie; protected $numTickets; public function __construct(Sale $sale, Movie $movie, int $numTickets) { $this->sale = $sale; $this->movie = $movie; $this->numTickets = $numTickets; } public function getSale() { return $this->sale; } public function getMovie() { return $this->movie; } public function getNumTickets() { return $this->numTickets; } } A bag of parameters that describe the event
  • 59. EventListener Processes the event class SaleListener { public function __construct(EntityManager $em) { $this->em = $em; } public function onSaleCreated(SaleEvent $event) { for ($i = 0; $i < $event->getNumTickets(); $i++) { $ticket = new Ticket(); $ticket->setMovie($event->getMovie()); $ticket->setSale($event->getSale()); $ticket->setRow(1); $ticket->setSeat(1); $this->em->persist($ticket); } } }
  • 61. Services A service is an object that does something: • Generate a thumbnail. • Generate a PDF. • A query to ElasticSearch. • Log something. • Send an email.
  • 62. Example class SaleLogger { private $logger; public function __construct(LoggerInterface $logger) { $this->logger = $logger; } public function log(Sale $sale) { $this->logger->info('Sold ' . count($sale->getTickets()) . ' tickets to ' . $sale->getFullName()); } } Where does this come from?
  • 63. Using services public function listAction(SaleLogger $saleLogger) { //… $saleLogger->log($sale); } Is injected with dependencies
  • 64. Explicit configuration # app/config/services.yml services: # explicitly configure the service AppLoggerSaleLogger: arguments: $logger: '@monolog.logger.request'
  • 65. Tagged services $taggedServices = $container->findTaggedServiceIds(‘app.my_tag’); foreach ($taggedServices as $id => $tags) { $definition->addMethodCall('callAMethod', array(new Reference($id))); } AppMyServices: resource: '../src/MyServices' tags: ['app.my_tag']
  • 67. Built in assertions /** * @ORMColumn(type="string") * @AssertLength(min=2) */ private $fullName; /** * @ORMColumn(type="string") * @AssertEmail() */ private $email; /** * @ORMColumn(type="text") * @AssertLength(max=100) */ private $question;
  • 68. Built in assertions There are 47 assertions From NotNull to Isbn And we can write our own assertions
  • 69. Use validators if ($form->isValid()) {} $author = new Author(); $validator = $this->get('validator'); $errors = $validator->validate($author); Dependency container
  • 70. Standalone use $email = ‘obama@usa.gov’; $emailConstraint = new AssertEmail(); $emailConstraint->message = 'Invalid email address'; $errorList = $this->get('validator')->validate( $email, $emailConstraint );
  • 72. Constraint class HasAvailableSeats extends Constraint { public $message = 'No {{ number }} available seats’; protected $movie; public function __construct($options) { $this->movie = $options['movie']; } public function getMovie() { return $this->movie; } public function validatedBy() { return get_class($this).'Validator'; } } No logic, data that describes the constraint Who validates this?
  • 73. class HasAvailableSeatsValidator extends ConstraintValidator { public function validate($value, Constraint $constraint) { $available = $constraint->getMovie()->getAvailableSeats(); if ($value > $available) { $this->context->buildViolation($constraint->message) ->setParameter('{{ number }}', $value) ->addViolation(); } } } Validator Validation logic
  • 74. APIs
  • 75.
  • 76. Up to level 2 Good use of HTTP verbs (GET, POST, PUT, DELETE, PATCH…) Structure based on resources (/movies, /movies/31). Use of HTTP Status codes (200, 201, 406, …). Use of representations (JSON, XML, …).
  • 77. Serializer: the idea $recipe = new Recipe(); $recipe->setName($content['name']); $recipe->setEnergy($content['energy']); $recipe->setServings($content['servings']); Request->Our object (manual deserialization) $responseData = [    'id' => $recipe->getId(),    'name' => $recipe->getName(),    'energy' => $recipe->getEnergy(),    'servings' => $recipe->getServings(),    ]; $response = new JsonResponse($responseData, 201); Our object->Request (manual serialization) Tedious!
  • 78. $response = new Response($serializer->serialize($recipe, 'json'), 201); $responseData = [    'id' => $recipe->getId(),    'name' => $recipe->getName(),    'energy' => $recipe->getEnergy(),    'servings' => $recipe->getServings(),    ]; $response = new JsonResponse($responseData, 201); Our object->Request (manual serialization) Serialize
  • 79. $recipe = $serializer->deserialize($content, Recipe::class, 'json'); $recipe = new Recipe(); $recipe->setName($content['name']); $recipe->setEnergy($content['energy']); $recipe->setServings($content['servings']); Request->Our object (manual deserialization) Deserialize
  • 81. Representation in API != DB { id: 9, name: "victoriaq", password: "encryptedPassword", email: "victoria@limenius.com", avatar: "avatar.jpg", twitter_handler: "vicqr", profile: { id: 19, bio: "My bio." } } I want this to be “username” I don’t want to expose it! Only in profile, not in list We want to prepend “thumb_” Only in version 2 of the API I’d like this to be bio:”My bio” We do this in the normalizer
  • 82. Annotations MaxDepth • Detect and limit the serialization depth • Especially useful when serializing large trees Groups • Sometimes, you want to serialize different sets of attributes from your entities • Groups are a handy way to achieve this need
  • 83. API Platform makes it very easy
  • 85. Admin on REST with API Platform