Maxence POUTORD
class Drink
{
protected $id;
protected $name;
protected $description;
public function __construct() {
//...
}
}
class Beer extends Drink
{
protected $alcohol;
protected $color;
protected $type;
public function __construct() {
//...
}
public function drinkIt() {
echo "glug glug";
}
}
class Beer
{
private $color;
//...
public function getColor() {
return $this->id;
}
public function setColor($color) {
$this->color = $color;
}
}
class Beer
{
//...
}
$myBeer = new Beer();
$myBeer->drinkIt(); //will output "glug glug"
$myBeer->setColor("blond");
$color = $myBeer->getColor();
class MySingleton
{
protected static $instance;
protected function __construct() { }
public static function getInstance()
{
if (!isset(self::$instance)) {
self::$instance = new self;
}
return self::$instance;
}
}
Hollywood Principle: "Don't call us, we'll call you"
Projects using Symfony: Drupal, Laravel, eZ Publish, Magento, BlaBlaCar, You****(You-Know-Who)
« Symfony is a set of PHP Components, a Web Application framework, a Philosophy, and a Community — all working together in harmony. »
So, Symfony2 is a MVC Framwork ?
# 1. install Symfony Installer (Linux/OS X)
$ sudo curl -LsS http://symfony.com/installer -o /usr/local/bin/symfony
$ sudo chmod a+x /usr/local/bin/symfony
# 1. install Symfony Installer (Windows)
$ php -r "file_put_contents('symfony', file_get_contents('http://symfony.com/installer'));"
# Download&Install Symfony
$ symfony new beerApp
# OR (choose a version)
$ symfony new beerApp 2.8
# 3. Create the first bundle
$ php app/console generate:bundle --format=yml
4 Folders:
Request to Response
# app/config/routing
conserto_beer:
resource: "@ConsertoBeerBundle/Resources/config/routing.yml"
prefix: /
# src/Conserto/BeerBundle/Resources/config/routing.yml
conserto_beer_show:
path: /{id}/show
defaults: { _controller: "ConsertoBeerBundle:Beer:show" }
conserto_beer_update:
path: /{id}/update
defaults: { _controller: "ConsertoBeerBundle:Beer:update" }
methods: [POST, PUT]
Lost ?
$ php app/console debug:router
$ php app/console router:match /beer/4/show
beer_show:
path: /beers/{_locale}/{brand}/{name}.{_format}
defaults: { _controller: ConsertoBundle:Beer:show, _format: html }
schemes: [https]
requirements:
_locale: en|fr
_format: html|rss
year: \d+
In a nutshell:
//Before
<?php echo $var; ?>
{# After #}
{{ var }}
<ul>
<?php
if (count($beers) > 0) {
foreach ($beers as $aBeer) {
echo "<li>".$aBeer->name." have ".$aBeer->alcohol." alcohol degree</li>";
}
} else {
echo "<li>no beer found</li>";
}
?>
</ul>
{% for aBeer in beers %}
- {{ aBeer.name }} have {{ aBeer.alcohol }} alcohol degree
{% else %}
- no beer found
{% endfor %}
{{ "now"|date("m/d/Y") }} // 2/11/2015
{{ 'abcd...'|reverse }} //...dcba
{{ '12345'|slice(1, 2) }} //23
{{ 101.51|round }} //102
{# Multiple filters #}
{{ 'abcd...'|slice(1, 2)|reverse }} //cb
{{ path('conserto_beer') }}
{{ path('conserto_beer_show', { 'id': 42 }) }}
{{ path('conserto_beer_show', { 'id': entity.id }) }}
{{ dump(myObject) }}
<!DOCTYPE html>
<html>
<head>...</head>
<body>
{% block body %}{% endblock %}
</body>
</html>
{# src/Conserto/Bundle/BeerBundle/Resources/views/Beer/index.html.twig #}
{% extends '::base.html.twig' %}
{% block body %}
{% if beer %}
Beer: {{ beer }}!
{% endif %}
{% endblock %}
# Generate entity with doctrine (also generate getters&setters):
$ php app/console generate:doctrine:entity
# Database creation/update
$ php app/console doctrine:schema:create
$ php app/console doctrine:schema:update
/**
* Beer
*
* @ORM\Table()
* @ORM\Entity(repositoryClass="Conserto\BeerBundle\Entity\BeerRepository")
*/
class Beer
{
/**
* @var integer
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var string
*
* @ORM\Column(name="name", type="string", length=255)
*/
private $name;
//...
$myBeer = new Beer();
$myBeer->setName('Kwak');
$myBeer->setAlcohol(8.4);
$anotherBeer = new Beer();
$anotherBeer->setName('Tripel Karmeliet');
$anotherBeer->setAlcohol(8.4);
//Step 1: Retrieve EntityManager service
$em = $this->getDoctrine()->getManager();
//Step 2: persist
$em->persist($myBeer);
$em->persist($anotherBeer);
//Step 3: Flush (generate&execute SQL)
$em->flush();
$em = $this->getDoctrine()->getManager();
$aBeer = $em->getRepository('ConsertoBeerBundle:Beer')->find($id);
$beers = $em->getRepository('ConsertoBeerBundle:Beer')->findAll();
$aBeer = $em->getRepository('ConsertoBeerBundle:Beer')->findOneByAbbey($abbey);
$beers = $em->getRepository('ConsertoBeerBundle:Beer')->findByAlcohol($alcohol);
$em = $this->getDoctrine()->getManager();
//Update
$aBeer = $em->getRepository('ConsertoBeerBundle:Beer')->find(42);
aBeer->setAlcohol = 8.4;
$em->flush();
//Delete
$aBeer = $em->getRepository('ConsertoBeerBundle:Beer')->find(51);
$em->remove($beer);
$em->flush();
//src\Conserto\BeerBundle\Repository\BeerRepository.php
public function findByAbbeyAndAlcohol($abbey, $alcohol)
{
$qb = $this->createQueryBuilder('b');
$qb->where('b.abbey = :abbey')
->setParameter('abbey', $abbey)
->andWhere('b.alcohol < :alcohol')
->setParameter('alcohol', $alcohol)
->orderBy('b.name', 'DESC');
return $qb
->getQuery()
->getResult()
;
}
//src\Conserto\BeerBundle\Form\BeerType.php
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name')
->add('alcohol')
->add('desciption')
;
}
//src\Conserto\BeerBundle\Controller\BeerController.php
$beer = $em->getRepository('ConsertoBeerBundle:Beer')->find($id);
$editForm = $this->createForm(BeerType::class, $beer, array(
'action' => $this->generateUrl('conserto_beer_update'),
'method' => 'PUT'
));
return $this->render('ConsertoBeerBundle:Beer:edit.html.twig', array(
'beer' => $beer,
'edit_form' => $editForm->createView()
));
{{ form(edit_form) }} {# Will generate a HTML Form #}
# app/config/config.yml
twig:
form_themes:
- 'bootstrap_3_layout.html.twig'
More information
<?php
use Symfony\Component\Validator\Constraints as Assert;
class Beer
{
//...
/**
* @var string
*
* @ORM\Column(name="name", type="string", length=255)
* @Assert\NotBlank()
* @Assert\Length(
* min = 2,
* minMessage = "Your Beer must be at least {{ limit }} characters long"
* )
*/
private $name;
Validation documentation
Use Dependency Injection pattern
# app/config/config.yml
services:
my_mailer:
class : Conserto\HelloBundle\Mailer
arguments: [sendmail]
class WhateverController extends Controller
{
public function sendEmailAction()
{
// ...
$mailer = $this->get('aMailer');
$mailer->send('contact@beerapp.io', ...);
}
}
Crud generation (Controller, Form, Views, Routes)
$ php app/console generate:doctrine:crud
Reverse engineering (generate entities from database)
$ php app/console doctrine:mapping:import --force AcmeBlogBundle xml
$ php app/console doctrine:mapping:convert annotation ./src
$ php app/console doctrine:generate:entities AcmeBlogBundle
$ alias sf='php app/console'
list | Lists commands |
debug:router | Displays current routes for an application |
doctrine:generate:entity | Generates a new Doctrine entity inside a bundle |
doctrine:generate:entities | Generates entity classes and method stubs from your mapping information |
doctrine:schema:update | Executes (or dumps) the SQL needed to update the database schema to match the current mapping metadata |
Please, stick the PSR (PHP Standard Recommendations)
http://www.php-fig.orgTools: PHP_CodeSniffer and PHP-CS-Fixer
# .editorconfig (editorconfig.org)
root = true
[*]
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[**.js]
indent_style = space
indent_size = 2
[**.php]
indent_style = space
indent_size = 4