Tips

by Joujou

03/06/2024

by Joujou

- 03/06/2024

Attributs

by Joujou

- 03/06/2024

Attributs

<?php

//...

use Symfony\Component\Routing\Annotation\Route;

class BlogController extends AbstractController
{
    /**
     * @Route("/blog", name="blog_list")
     */
    public function list(): Response
    {
        // ...
    }
}

Avant

by Joujou

- 03/06/2024

Attributs

<?php

// ...

    /**
     * @Route("/blog", name="blog_list")
     */

// ...

Avant

Après

<?php

// ...

use Symfony\Component\Routing\Attribute\Route;

class BlogController extends AbstractController
{
    #[Route('/blog', name: 'blog_list')]
    public function list(): Response

by Joujou

- 03/06/2024

Attributs

Symfony 6.4+

  • Basiques (Route, Doctrine, etc.)
  • AsController
  • CurrentUser (seulement dans les controllers)
  • Autowire
  • AutoconfigureTag
  • TaggedIterator
  • When
  • AsDecorates
  • AsCronTask
  • AsPeriodicTask
  • AsEventListener
  • Cache
  • MapQueryParameter
  • MapRequestPayload

by Joujou

- 03/06/2024

Attributs

AsController

<?php 

// ...
use Symfony\Component\HttpKernel\Attribute\AsController;

#[AsController]
class HelloController
{
    #[Route('/hello', name: 'hello', methods: ['GET'])]
    public function index(): Response
    {
        // ...
    }
}

Pas de configuration YAML

by Joujou

- 03/06/2024

Attributs

CurrentUser

<?php 

// ...
use Symfony\Component\Security\Http\Attribute\CurrentUser;

#[AsController]
class HelloController
{
    #[Route('/hello', name: 'hello', methods: ['GET'])]
    public function index(#[CurrentUser] ?User $user): Response
    {
        // ...
    }
}

⚠️ Uniquement dans les controllers ⚠️

by Joujou

- 03/06/2024

Attributs

Autowire

<?php

//...

use Symfony\Component\DependencyInjection\Attribute\Autowire;

class MessageGenerator
{
    public function __construct(
        #[Autowire(service: 'monolog.logger.request')]
        private LoggerInterface $logger,
    ) {
        // ...
    }
}

by Joujou

- 03/06/2024

Attributs

AutoconfigureTag

<?php

//...

use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag;

#[AutoconfigureTag('app.custom_tag')]
interface CustomInterface
{
    // ...
}

Plus besoin de la configuration YAML

services:
    _instanceof:
        App\Security\CustomInterface:
            tags: ['app.custom_tag']

by Joujou

- 03/06/2024

Attributs

TaggedIterator

<?php

//...

use Symfony\Component\DependencyInjection\Attribute\TaggedIterator;

class HandlerCollection
{
    public function __construct(
        #[TaggedIterator('app.custom_tag')]
        iterable $handlers
    ) {
        // ...
    }
}

Plus besoin de la configuration YAML

by Joujou

- 03/06/2024

Attributs

When

<?php

//...

use Symfony\Component\DependencyInjection\Attribute\When;

#[When(env: 'prod')]
class UberallReviewClient
{
    // ...
}

#[When(env: 'dev')]
#[When(env: 'test')]
class DecoratorGoogleMyBusinessReviewClient
{
    // ...
}

by Joujou

- 03/06/2024

Attributs

AsDecorator

<?php

//...

#[AsDecorator(decorates: UberallReviewClient::class)]
class DecoratorGoogleMyBusinessReviewClient implement ReviewClientInterface
{
	public function __construct(
        #[AutowireDecorated] private object $inner
    ) {
        // ...
    }

    public function getList(Store $store): array
    {
        return $this->inner->getList($store);
    }
	
}

Plus besoin de la configuration YAML

by Joujou

- 03/06/2024

Attributs

AsCronTask

<?php

//...

use Symfony\Component\Scheduler\Attribute\AsCronTask;

#[AsCronTask('0 0 * * *')]
class MyTask
{
	public function __invoke()
    {
        // ...
    }
}

#[AsCronTask('0 0 * * *', method: 'foo', arguments: ['bar' => 'truite'])]
class MyTask
{
	public function foo(string $bar): void
    {
        // ...
    }
}

by Joujou

- 03/06/2024

Attributs

AsPeriodicTask

<?php
//...

use Symfony\Component\Scheduler\Attribute\AsPeriodicTask;

#[AsPeriodicTask(frequency: '1 day', from: '2024-01-01', until: '2024-06-12')]
class MySeasonalTask
{
    public function __invoke(): void
    {
        // ...
    }
}

by Joujou

- 03/06/2024

Attributs

AsEventListener

<?php
//...

use Symfony\Component\EventDispatcher\Attribute\AsEventListener;

#[AsEventListener(event: CustomEvent::class, method: 'onCustomEvent')]
#[AsEventListener(event: 'bar', method: 'onBarEvent')]
final class MyMultiListener
{
    public function onCustomEvent(CustomEvent $event): void
    {
        // ...
    }

    public function onBarEvent(): void
    {
        // ...
    }
    
    #[AsEventListener(event: 'foo', priority: 42)]
    public function onFoo(): void
    {
        // ...
    }
}

by Joujou

- 03/06/2024

Attributs

Cache

<?php
//...

use Symfony\Component\HttpKernel\Attribute\Cache;

#[Cache(public: true, maxage: 3600, mustRevalidate: true)]
public function index(): Response
{
    return $this->render('blog/index.html.twig', []);
}

by Joujou

- 03/06/2024

Attributs

MapQueryParameter

<?php
//...

use Symfony\Component\HttpKernel\Attribute\MapQueryParameter;

public function dashboard(
    #[MapQueryParameter(
        filter: \FILTER_VALIDATE_REGEXP,
        options: ['regexp' => '/^\w+$/']
    )] string $firstName,
    #[MapQueryParameter] string $lastName,
    #[MapQueryParameter(filter: \FILTER_VALIDATE_INT)] int $age,
): Response
{
    // ...
}

by Joujou

- 03/06/2024

Attributs

MapRequestPayload

<?php
//...

use App\Model\UserDto;
use Symfony\Component\HttpKernel\Attribute\MapRequestPayload;

public function dashboard(
    #[MapRequestPayload] UserDto $userDto
): Response
{
    // ...
}

by Joujou

- 03/06/2024

Miscellaneous

by Joujou

- 03/06/2024

Promotion du Constructeur

<?php

class UberallReviewClient implements ReviewClientInterface
{
    private string $baseUri;

    public function __construct(
        private EmojiService $emojiService,
        private LoggerInterface $reviewLogger,
        private int $apiKey
    ) {
        $this->baseUri = 'dummy';
    }
}

by Joujou

- 03/06/2024

Readonly

<?php

class Review
{
    public function __construct(
        readonly public string $id,
        readonly public string $author,
        public ?DateTimeInterface $publishedAt = null,
    ) {
    }
    
    public function publish(): self
    {
        $this->$publishedAt = new \DateTime();
    }
}

Propriétés

by Joujou

- 03/06/2024

Readonly

<?php

readonly class Review
{
    public function __construct(
        public string $id,
        public string $author,
        public ?DateTimeInterface $publishedAt,
    ) {
    }
}

Classes

by Joujou

- 03/06/2024

Union / Intersection types

<?php

class Example {
    private int|float $foo;

    public function squareAndAdd(float|int $bar): int|float
    {
        return $bar ** 2 + $foo;
    }
    
    function countAndIterate(\Iterator&\Countable $value): void
    {
        foreach($value as $val) {}
        \count($value);
    }
}

by Joujou

- 03/06/2024

Nullsafe Operator

<?php

// Avant

if (null === $repository)) {
    $result = null;
} else {
    $user = $repository->getUser(5);

    if (!$user instanceof User)) {
        $result = null;
    } else {
        $result = $user->name;
    }
}

// Après

$result = $repository?->getUser(5)?->name;

by Joujou

- 03/06/2024

Match

<?php

private function getMedia(Store $store, string $type): ?Media
{
    return match ($type) {
  	    self::IMAGE => $store->getImageStore(),
  	    self::IMAGE_EXTERIOR => $store->getImageStoreExterior(),
  	    self::IMAGE_INTERIOR => $store->getImageStoreInterior(),
  	    default => throw new \InvalidArgumentException(
  		    'This type is not supported : ' . $type
  	    ),
    };
}

by Joujou

- 03/06/2024

Arguments nommés

<?php

$reviewDTOs[] = new Review(
    id: $review->getId(),
    author: $review->getAuthor(),
    content: $review->getContent(),
    rate: $review->getRate() ?: 0
);

by Joujou

- 03/06/2024

Arguments nommés

<?php

$filter = new Filter(
    null,
    null,
    $storeIds ?? null,
    $directories ?? null,
    $suppliers ?? $brandSuppliers,
    null,
    $resourceDto->getLimit(),
    null,
    null,
    null,
    null,
    $resourceDto->getSortBy(),
    $resourceDto->getOrderBy(),
    null,
    $resourceDto->getPageToken()
);

Avant

by Joujou

- 03/06/2024

Arguments nommés

<?php

$filter = new Filter(
    storeIds: $storeIds ?? null,
    directories: $directories ?? null,
    supplierSlugs: $suppliers ?? $brandSuppliers,
    limit: $resourceDto->getLimit(),
    orderBy: $resourceDto->getSortBy(),
    orderDir: $resourceDto->getOrderBy(),
    pageToken: $resourceDto->getPageToken()
);

Après

by Joujou

- 03/06/2024

Enumération

<?php

enum Suit
{
    case Hearts;
    case Diamonds;
    case Clubs;
    case Spades;
}

function pick_a_card(Suit $suit)
{
    /* ... */
}

$val = Suit::Diamonds;

// OK
pick_a_card($val);

// OK
pick_a_card(Suit::Clubs);

// TypeError: pick_a_card(): Argument #1 ($suit) must be of type Suit, string given
pick_a_card('Spades');

Basique

by Joujou

- 03/06/2024

Enumération

<?php

enum Suit: string
{
    case Hearts = 'H';
    case Diamonds = 'D';
    case Clubs = 'C';
    case Spades = 'S';
}

print Suit::Clubs->value; // Affiche "C"

$hearts = Suit::tryFrom('H'); // La valeur est Suit::Hearts

Backed

by Joujou

- 03/06/2024

Enumération

<?php

trait EnumToArray
{
    public static function names(): array
    {
        return \array_column(self::cases(), 'name');
    }

    public static function values(): array
    {
        return \array_column(self::cases(), 'value');
    }

    public static function asArray(): array
    {
        if (empty(self::values())) {
            return self::names();
        }

        if (empty(self::names())) {
            return self::values();
        }

        return \array_column(self::cases(), 'value', 'name');
    }
}

Backed

by Joujou

- 03/06/2024

Enumération

<?php

enum Suit: string
{
    use EnumToArray;

    case Hearts = 'H';
    case Diamonds = 'D';
    case Clubs = 'C';
    case Spades = 'S';
}

Suit::names() => ['Hearts', 'Diamonds', 'Clubs', 'Spades']

Suit::values() => ['H', 'D', 'C', 'S']

$test = 'H';

if (\in_array($test, Suit::values(), true)) {
    // ...
}

Backed

by Joujou

- 03/06/2024

Constante

<?php

class Dummy {
    final const string NAME = 'dummy';
}

$name = 'NAME';

echo Dummy::{$name}; // Affiche 'dummy'

Merci

Questions ?

Made with Slides.com