Marcel Krüger

Ein Symfony 5 Cheatsheet

Ein unvollständiges Symfony 5 Codeschnipsel-Sammelsurium

21. Jul. 2020

Hier gibt's einige Codeschnipsel, die ich regelmäßig in irgendeiner Art und Weise brauche wenn ich mich mit Symfony beschäftige. Da ich super-vergesslich bin, hilft mir dieser Eintrag hoffentlich nicht mehr alle möglichen Projekte und Dateien durchzusuchen, wenn ich was brauche :)

Dieses Cheatsheet basiert auf Symfony 5

Controller

Routen

Benamte Route die ein Twig-Template zurück gibt:

/**
 * @Route("/project", name="index")
 */
public function index()
{
    return $this->render('project/index.html.twig', [
        'controller_name' => 'ProjectController',
    ]);
}

Eine API-Route die JSON zurück gibt. Die Route ist nur gültig für POST-Requests:

/**
 * @Route("/project/toggle", name="project_toggle", methods={"POST"})
 */
public function index()
{
    return $this->json(['value' => rand(0, 10)]);
    // or:
    // return new JsonResponse(['value' => rand(0, 10)]);
}

Route mit Requirements an Parameter

/**
 * @Route("/project/{id}", requirements={"id"="\d+"}, name="project_show")
 */
public function show($id)
{
    return new Response("Test $id");
}

Auch möglich: Requirements direkt nach Parameter innerhalb von < > notieren:

/**
 * @Route("/project/{id<\d+>}", name="project_show")
 */

Parameter-Konverter

Der Parameter-Konverter macht automatisch Entitäts-Objekte aus Routen-Parametern. In diesem Beispiel wird automatisch ein BlogPost Objekt erzeugt sofern der Parameter slug einem Post zugeordnet werden kann:

/**
 * @Route("/blog/{slug}", name="blog_show")
 */
public function show(BlogPost $post)
{
    // $post is the object whose slug matches the routing parameter

    // ...
}

Es genügt einen Type Hint beim Parameter anzugeben. Gibt es keinen Post, wird automatisch eine 404-Seite erzeugt.

Hier ein Bsp. wenn man mehrere Parameter hat, die konvertiert werden sollen. Einer muss speziell ausgezeichnet werden:

/**
* @Route("/blog/{id}/comments/{comment_id}")
* @Entity("comment", expr="repository.find(comment_id)")
*/
public function show(Post $post, Comment $comment)
{
    // ...
}

Mehr Infos zum Parameterkonverter gibt es hier.

Redirects

// ...
public function index()
{
    // redirects to the "homepage" route
    return $this->redirectToRoute('homepage');

    // redirectToRoute is a shortcut for:
    // return new RedirectResponse($this->generateUrl('homepage'));

    // does a permanent - 301 redirect
    return $this->redirectToRoute('homepage', [], 301);

    // redirect to a route with parameters
    return $this->redirectToRoute('app_lucky_number', ['max' => 10]);

    // redirects to a route and maintains the original query string parameters
    return $this->redirectToRoute('blog_show', $request->query->all());

    // redirects externally
    return $this->redirect('http://symfony.com/doc');
}

Flash messages

Offizielle Doku zu Flash-Messages

Flash-Messages dienen zum einmaligen Anzeigen von Meldungen.

Message erstellen

use Symfony\Component\HttpFoundation\Request;

public function update(Request $request)
{
    $this->addFlash('notice', 'Your changes were saved!');
    // $this->addFlash() is equivalent to $request->getSession()->getFlashBag()->add()
}

Message anzeigen

{# read and display just one flash message type #}
{% for message in app.flashes('notice') %}
    <div class="flash-notice">
        {{ message }}
    </div>
{% endfor %}

{# read and display several types of flash messages #}
{% for label, messages in app.flashes(['success', 'warning']) %}
    {% for message in messages %}
        <div class="flash-{{ label }}">
            {{ message }}
        </div>
    {% endfor %}
{% endfor %}

{# read and display all flash messages #}
{% for label, messages in app.flashes %}
    {% for message in messages %}
        <div class="flash-{{ label }}">
            {{ message }}
        </div>
    {% endfor %}
{% endfor %}

Assets

Im Ordner public gespeichertes Dateien referenzieren

Folgender Schnipsel referenziert <symfony_root>/public/css/app.css.

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

Mit webpack-encore erzeugte Dateien referenzieren

Offizielle webpack-encore Doku

Die webpack.config.js sollte Zeilen wie diese enthalten:

.addEntry('app', './assets/js/app.js')
.addEntry('plot', './assets/js/plot.js')
.addEntry('scene', './assets/js/scene.js')

In Twig können die Resourcen mittels dem folgenden Code inkludiert werden:

{{ encore_entry_script_tags('app') }} {# Creates script tags #}
{{ encore_entry_link_tags('app') }} {# Creates CSS (link) tags #}

URLs

<a href="{{ path('index') }}">Index</a>
<a href="{{ path('project_show', {id: 2}) }}">Show project</a>

Twig

Blöcke erweitern aus Child-Template:

{% block javascripts %}
    {{ parent() }}

    <script>
        ...
    </sctipt>
{% endblock %}

Datenbank und Doctrine

Doctrine Doku

Objekte holen

$repository = $this->getDoctrine()->getRepository(Product::class);

// look for a single Product by its primary key (usually "id")
$product = $repository->find($id);

// look for a single Product by name
$product = $repository->findOneBy(['name' => 'Keyboard']);
// or find by name and price
$product = $repository->findOneBy([
    'name' => 'Keyboard',
    'price' => 1999,
]);

// look for multiple Product objects matching the name, ordered by price
$products = $repository->findBy(
    ['name' => 'Keyboard'],
    ['price' => 'ASC']
);

// look for *all* Product objects
$products = $repository->findAll();

Objekte speichern

/**
 * @Route("/project/store", name="project_store", methods={"POST"})
 */
public function store()
{
    $project = new Project();
    $project->setName('test');

    $entityManager = $this->getDoctrine()->getManager();
    $entityManager->persist($project);
    $entityManager->flush();

    return $this->render('project/index.html.twig', [
        'controller_name' => 'ProjectController',
    ]);
}

Objekte ändern

/**
* @Route("/product/edit/{id}")
*/
public function update($id)
{
    $product = $entityManager->getRepository(Product::class)->find($id);

    if (!$product) {
        throw $this->createNotFoundException(
            'No product found for id '.$id
        );
    }

    $entityManager = $this->getDoctrine()->getManager();
    $product->setName('New product name!');
    $entityManager->flush();

    return $this->redirectToRoute('product_show', [
        'id' => $product->getId()
    ]);
}

Objekte löschen

$entityManager->remove($product);
$entityManager->flush();