KPHP
KPHP

Reputation: 1

Generator with factory method

I have a problem with the proper arrangement of services.I want to create a generator that, thanks to the provider, will create the corresponding generator object through the factory method.In my mind it would more or less look like this:

API Request with provider -> GeneratorController::generate -> factory method -> Generator class service

I would like to generate a pdf file using twig, but I have a problem with the ContainerInterface.I'm afraid that my concept of operation is not correct. Is anyone able to tell me if I am going in the right direction?

I would like to make a pdf generator that is created through a provider and generator classes.

GeneratorController

public function generate($provider, Request $request): Response
{
    $generator = $this->factory->createGenerator($provider);
    $content = json_decode($request->getContent(), true);
    $generator->generate($content['params']);
    
    return new JsonResponse($generator->getData());
}

GeneratorFactory

class GeneratorFactory
{
    public function createGenerator($generator): Generator
    {
        $generatorName = "App\\Generators\\" . ucwords($generator) . "\\Generator";

        if (!class_exists($generatorName)) {
            throw new \Exception("We dont find genarator with name: " . $generator);
        }

        return new $generatorName;
    }
}

Generator from factory

 public function __construct()
    {
        $this->object = new GeneratorObject;
        $this->validator = new Validator;
        $this->service = new PdfService();
    }
    public function generate(array $params): void
    {
        $valided = $this->validator->Validate($params);
        if (!$valided) {
            throw new Exception("Invalid parameters", 1);
        }
        $this->setDataToObject($params);
        $pdf = $this->service->createPdf($this->object);
        $this->data = $pdf;
    }

Service for pdf

public function createPdf(GeneratorObject $pdfObject): string
{
    $url = '';
    $html = $this->templating->render('pdf/index.html.twig',[$pdfObject]);

    return $url;
}

Upvotes: 0

Views: 374

Answers (2)

KPHP
KPHP

Reputation: 1

I think I have solved my problem. I changed the concept a little bit. I divided the services accordingly and now it injects the service in the controller. When injecting the service, I made an autoload for twig and set it as a variable of the object created from the factory method.Now it looks like this

Controller

public function generate($provider, Request $request, GeneratorFactory $factory): Response
{
    $generator = $factory->createGenerator($provider);
    $factory->setTwig($generator);
    $content = json_decode($request->getContent(), true);
    $generator->generate($content['params']);

    return new JsonResponse($generator->getData());
}

Factory method

public function __construct(Environment $twig)
{
    $this->twig = $twig;
}

Object from factory

/**
 * generate
 *
 * @param  array $params
 * @return void
 */
public function generate(array $params): void
{
    $valided = $this->validator->Validate($params);
    if (!$valided) {
        throw new Exception("Invalid parameters", 1);
    }
    $this->setDataToObject($params);
    $pdf = $this->createPdf($this->object);
    $this->data = $pdf;
}
/**
 * createPdf
 *
 * @param  object $params
 * @return string
 */
private function createPdf(object $params): string
{
    $pdfHtml = $this->twig->render('pdf/cv.html.twig',[$params]);

    return '';
}

Upvotes: 0

Bademeister
Bademeister

Reputation: 886

If I understand right, you should use a tagged iterator. I haven't found a nice example/article. So here is an untested example. But tagged iterator is the keyword for more information.

For #[TaggedIterator] and #[AutoconfigureTag] you need at least PHP 8 and Symfony 5.4.

<?php

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag;
use Symfony\Component\DependencyInjection\Attribute\TaggedIterator;

#[AutoconfigureTag('app.custom_generator_tag')]
interface GeneratorInterface
{
    public function support(string $format): bool;
    public function generate(): string;
}

abstract class GeneratorAbstract implements GeneratorInterface
{
    public function support(string $format): bool
    {
        return strtoupper($format) === $this::FORMAT;
    }
}

class PdfGenerator extends GeneratorAbstract
{
    public const FORMAT = 'PDF';

    public function __construct(/* autowire services */) { }

    public function generate(): string
    {
        return 'pdf file';
    }
}

class WordGenerator extends GeneratorAbstract
{
    public const FORMAT = 'WORD';

    public function __construct(/* autowire services */) { }

    public function generate(): string
    {
        return 'word file';
    }
}

class GeneratorFactory
{
    /**
     * @var GeneratorInterface[]
     */
    private array $generators;

    public function __construct(#[TaggedIterator('app.custom_generator_tag')] $generators)
    {
        $this->generators = $generators;
    }

    public function generate(string $format): string
    {
        foreach ($this->generators as $generator) {
            if ($generator->support($format)) {
                return $generator->generate();
            }
        }

        throw new \Exception('Generator not found');
    }
}

class Generatorcontroller extends AbstractController
{
    public function __construct(private GeneratorFactory $generatorFactory) {}

    public function generateAction()
    {
        return $this->generatorFactory->generate('pdf');
    }
}

Upvotes: 0

Related Questions