Making Web Apps with
PHP Symfony

Softwerkskammer Magdeburg

Hendrik Pilz


<?php print_r($me); ?>
                    
stdClass Object
(
    [name] => Hendrik
    [worksAt] => rundum.digital
    [codingSince] => 1998
    [languages] => Array
        (
            [0] => PHP
            [1] => HTML
            [2] => CSS
            [3] => JS
            [4] => Java
            [5] => SQL
            [6] => ...
        )
)                        
                    

Was ist Symfony?

«Symfony is
a set of PHP Components,
a Web Application framework,
a Philosophy,
and a Community —
all working together in harmony.»

Das Framework

  • Model-View-Controller
  • ORM mit Doctrine
  • Templates mit Twig
  • Konfiguration mittels Annotationen (meistens)

Agenda

  • Setup
  • Projekt BookDB
  • Let's make it
  • Zusammenfassung

Setup

Projekt BookDB

  • Datenbank für Bücher, Authoren und Rezensionen

Let's make it


$ mkdir bookdb
$ cd bookdb
$ composer create-project symfony/website-skeleton .
$ php bin/console server:run
                    

Datenbank-Verbindung


DATABASE_URL=mysql://user:password@127.0.0.1:3306/dbname
                    

.env-Datei im Projektverzeichnis


$ php bin/console doctrine:database:create
                    

optional

Entity User


$ php bin/console make:user
$ php bin/console make:migration
$ php bin/console doctrine:migrations:migrate
                    

Registration Form


$ php bin/console make:registration-form
                    

http://localhost:8000/register


$ php bin/console doctrine:query:sql "SELECT * FROM user"
                    

Login Form


$ php bin/console make:auth
                    

http://localhost:8000/login

Der erste Controller


$ php bin/console make:controller
                    

onAuthenticationSuccess() in Authenticator-Klasse anpassen

Das erste Entity: Book


$ php bin/console make:entity
$ php bin/console make:migration
$ php bin/console doctrine:migrations:migrate
                    

Weitere Entities

  • Author
  • Publisher
  • Review

Entities verbinden

  • Book Author @ManyToMany
  • Book Publisher @ManyToOne
  • Book Review @OneToMany
  • Review User @ManyToOne

$ php bin/console make:entity
$ php bin/console make:migration
$ php bin/console doctrine:migrations:migrate
                    

Ein Blick in die Datenbank

Datenbank-Schema

CRUD

  • Create form
  • List view (Read)
  • Update form
  • Delete form

$ php bin/console make:crud
                    

Object could not be converted to string


public function __toString() {
    return $this->title;
}
                    

Book.php, bei anderen Entities entsprechend anpassen

Bootstrap hinzufügen (1)

  • unterstützt v3 und v4

<link rel="stylesheet" type="text/css"
      href="{{ asset('css/bootstrap.min.css') }}" />
                    

im <head> in templates/base.html.twig

Bootstrap hinzufügen (2)


<script type="text/javascript"
        src="{{ asset('js/bootstrap.min.js') }}"></script>
{% block javascripts %}{% endblock %}
                    

vor </body> in templates/base.html.twig

Bootstrap hinzufügen (3)


{% form_theme form 'bootstrap_4_layout.html.twig' %}
                    

in allen _form.html.twig


{% form_theme form 'bootstrap_3_layout.html.twig' %}
{% form_theme form 'bootstrap_3_horizontal_layout.html.twig' %}
{% form_theme form 'bootstrap_4_horizontal_layout.html.twig' %}
                    

alternative Form-Templates

Review Form anpassen (1)

  • Eingabe für "User" entfernen
  • NumberType für "rating" mit "html5" = true

public function buildForm(FormBuilderInterface $builder,
                          array $options) {
     $builder->add('title')
             ->add('text')
             ->add('rating', NumberType::class, [
                 'html5' => true
             ])
             ->add('book');
}
                    

ReviewType.php

Review Form anpassen (2)

  • Range-Constraint für "rating" in Review-Entity definieren

use Symfony\Component\Validator\Constraints as Assert;
                    

/**
 * @ORM\Column(type="integer")
 * @Assert\Range(min = 1, max = 10)
 */
private $rating;
                    

Review.php

Review Form anpassen (3)

  • User im Controller zuweisen

/**
 * @Route("/new", name="review_new", methods={"GET","POST"})
 */
public function new(Request $request): Response
{
    $review = new Review();
    $review->setUser($this->getUser());
    $form = $this->createForm(ReviewType::class, $review);
    // [...]
}
                    

ReviewController.php

CUD-Operationen schützen


use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
                    

/**
 * @Route("/new", name="review_new", methods={"GET","POST"})
 * @Security("is_granted('ROLE_USER')")
 */
public function new(Request $request): Response
{
    // [...]
}
                    

in allen Controller-Klassen nach Bedarf

Security Voter für Reviews (1)

  • User dürfen nur ihre eigenen Reviews bearbeiten

$ php bin/console make:voter
                    

Security Voter für Reviews (2)


class ReviewVoter extends Voter {
    protected function supports($attribute, $subject) {
        return in_array($attribute, ['EDIT'])
               && $subject instanceof Review;
    }

    protected function voteOnAttribute($attribute, $subject,
                                    TokenInterface $token) {
        /* @var $subject Review */
        $user = $token->getUser();
        // if the user is anonymous, do not grant access
        if (!$user instanceof UserInterface) {
            return false;
        }

        switch ($attribute) {
            case 'EDIT':
                return $subject->getUser()->getUsername()
                === $user->getUsername();
        }

        return false;
    }
}
                    

ReviewVoter.php

Security Voter für Reviews (3)


public function edit(Request $request,
                     Review $review): Response
{
    $this->denyAccessUnlessGranted('EDIT', $review);

    // ...
}
                    

ReviewController.php

REST API (1)


$ composer require api
                    

REST API (2)

  • Entities als API-Resourcen deklarieren

/**
 * @ORM\Entity(repositoryClass="App\Repository\BookRepository")
 * @ApiResource
 */
class Book {
    // ...
}
                    

REST API (3)

  • Online API-Dokumentation unter /api
  • oder im OpenAPI-Format

$ php bin/console api:openapi:export > api.json
$ php bin/console api:openapi:export --yaml > api.yaml
                    

Zusammenfassung

  • Benutzte Komponenten:
    • Console (inkl. MakerBundle)
    • Dependency Injection
    • Doctrine ORM
    • Form
    • Routing
    • Security
    • Templating
    • Validator
    • Developer Server & Toolbar
    • REST API

Was gibt es noch?

symfony.com/doc/current/components/index.html

Vielen Dank!

@HendrikPilz

Diese Präsentation ist hier verfügbar
www.hepisec.de/swk-symfony/