Bonjour,

Je suis en train de me former à Symfony 4 et je souhaite utiliser le pattern Factory pour instancier un objet si 1 des 3 éléments passés en paramètre ne sont pas null. Dans mon cas, je suis en train de faire une API REST.

Ce que je fais

J'ai une méthode static creerCommune dans la factory CommuneFactory qui est censée recevoir 3 paramètres (insee, code postal et nom) et où j'utilise l'injection de dépendance dans le constructeur. Mais, bien entendu, comme il s'agit d'une méthode static, le constructeur n'est jamais appelé.

    private static $_translator;

    public function __construct(TranslatorInterface $translator)
    {
        self::$_translator = $translator;
    }

    public static function creerCommune(string $insee = null,
                                                                       string $codePostal = null,
                                                                       string $nom = null)
    {
        if (null === $insee && null === $codePostal && null === $nom) {
            throw new MissingElementException(
                self::$_translator->trans('elementManquant') . " : " .
                self::$_translator->trans('codeInsee') . ", " .
                self::$_translator->trans('codePostal') . ", " .
                self::$_translator->trans('nomCommune')
            );
        }

        return new Commune($insee, $codePostal, $nom);
    }

J'appelle cette méthode comme suit :

CommuneFactory::creerCommune(
    $request->get("insee"),
    $request->get("codePostal"),
    $request->get("nom")
);

Ce que je veux

Ma Factory doit juste créer un objet Commune si et seulement si au moins 1 des 3 éléments (insee, code postal ou nom) sont remplis. Sinon, je lève une exception qui renvoie un message grâce à TranslatorInterface.

En plus de la factory, j'avais pensé à utiliser le singleton ou de créer une classe de validator et d'y déporter ma condition... Je ne vois, à priori, aucune autre solution. Si vous en avez une, je suis preneur !

Ce que j'obtiens

FatalThrowableError
Call to a member function trans() on null

self::$_translator est donc forcément toujours null...

4 réponses


Finalement, j'opte pour une classe Validator. Cependant, l'autowiring ne fonctionne pas mieux... J'ai ce genre d'erreur :

FatalThrowableError
Type error: Too few arguments to function App\Validator\CommuneValidator::__construct(), 0 passed in /var/www/html/sf4proj/src/Factory/CommuneFactory.php on line 34 and exactly 2 expected

Mon code :

class CommuneValidator
{
    private $_translator;
    private $_validator;

    public function __construct(TranslatorInterface $translator,
                                ValidatorInterface $validator)
    {
        $this->_translator = $translator;
        $this->_validator = $validator;
    }
    //...
}

Salut,

L'erreur t'indique qu'aucun paramètres n'est passer à ton constructeur. Je peut pas expliquer pourquoi l'autowire ne fonctionne pas car cela met déjàs arriver mais je n'est pas eu le temps de me pencher sur l'autowire. Mais en générale je déclare des services lorsque j'ai besoin de l'injection de dépendance dans le constructeur.

Pour que tu puisse injecter ces paramètres il faut que tu déclare un service puis que tu passe en argument les deux objets que tu souhaite.

Dans ton cas sa serait :

nom.du.service:
    class: Path\To\Your\CommuneValidator
    arguments: ['@translator', '@validator']

Pour savoir si ton service est bien enregistré tu peut utiliser la commande sa aide à voir les services enregister :

php bin/console debug:container

Salut,

Je ne comprends pas très bien pourquoi tu veux un factory puisque la classe que tu retournes est toujours "Commune" ou sinon tu lances une exception.

Donc pour moi il suffit d'utiliser l'injection de dépendances sans faire de static avec un constructeur et l'autowiring à "on" et de faire ta condition dans une methode.

Pour le reste, tu fais un catch de ton exception en retour de ton service.

Si demain tu dois utiliser un objet Commune ou un objet CommuneTmp suivant la condition de ton factory, alors là, je comprends.

Bonjour et désolé pour le retard.

Merci à tous les 2 d'avoir pris le temps de répondre.

@ksta J'avais également essayé de faire cela, mais visiblement, ça ne fonctionnait pas non plus. Du coup, j'ai ajouté, au constructeur de mon controller, le CommuneValidator (où je l'affecte de cette manière $this->_validator = $validator;). Ensuite, j'utilise $this->_validator->validerCommune($commune); quand j'en ai besoin. Dans le constructeur de CommuneValidator, j'ai le paramètre TranslatorInterface $translator.

@Julien En fait, il s'agit, dans un premier temps, d'écrire un exemple pour les développeurs.