Skip to content

Simplify TypeGenerator dependencies #843

@murtukov

Description

@murtukov
Q A
RFC? yes
Version/Branch 0.14

The TypeGeneratorclass has a lot of dependencies and the most of them are Symfony parameters. The current service declaration looks like this:

Overblog\GraphQLBundle\Generator\TypeGenerator:
arguments:
- "%overblog_graphql.class_namespace%"
- "%overblog_graphql.cache_dir%"
- "%overblog_graphql_types.config%"
- '@Overblog\GraphQLBundle\Generator\TypeBuilder'
- '@Symfony\Contracts\EventDispatcher\EventDispatcherInterface'
- "%overblog_graphql.use_classloader_listener%"
- "%kernel.cache_dir%"
- "%overblog_graphql.cache_dir_permissions%"

and the class constructor with properties looks like this:

private static bool $classMapLoaded = false;
private ?string $cacheDir;
protected int $cacheDirMask;
private array $configs;
private bool $useClassMap;
private ?string $baseCacheDir;
private string $classNamespace;
private TypeBuilder $typeBuilder;
private EventDispatcherInterface $eventDispatcher;
public function __construct(
string $classNamespace,
?string $cacheDir,
array $configs,
TypeBuilder $typeBuilder,
EventDispatcherInterface $eventDispatcher,
bool $useClassMap = true,
?string $baseCacheDir = null,
?int $cacheDirMask = null
) {
$this->cacheDir = $cacheDir;
$this->configs = $configs;
$this->useClassMap = $useClassMap;
$this->baseCacheDir = $baseCacheDir;
$this->typeBuilder = $typeBuilder;
$this->eventDispatcher = $eventDispatcher;
$this->classNamespace = $classNamespace;
if (null === $cacheDirMask) {
// Apply permission 0777 for default cache dir otherwise apply 0775.
$cacheDirMask = null === $cacheDir ? 0777 : 0775;
}
$this->cacheDirMask = $cacheDirMask;
}

in my opinion it looks messy. What I would like to do is to pass all the parameter dependencies together, either as an array or an object and maybe rename some of them to make them more descriptive. I considered 3 different ways to do that, but I will describe here only 1 of them, which I think is the best way:

Change the service declaration to pass all the parameters as an array:

Overblog\GraphQLBundle\Generator\TypeGenerator:
    arguments:
        - '@Overblog\GraphQLBundle\Generator\TypeBuilder'
        - '@Symfony\Contracts\EventDispatcher\EventDispatcherInterface'
        - classNamespace: "%overblog_graphql.class_namespace%"
          cacheDir:       "%overblog_graphql.cache_dir%"
          config:         "%overblog_graphql_types.config%"
          useClassMap:    "%overblog_graphql.use_classloader_listener%"
          baseCacheDir:   "%kernel.cache_dir%"
          cacheDirMask:   "%overblog_graphql.cache_dir_permissions%"

To make the service declaration more readable we could use explicit arguments:

Overblog\GraphQLBundle\Generator\TypeGenerator:
    arguments:
        $typeBuilder:     '@Overblog\GraphQLBundle\Generator\TypeBuilder'
        $eventDispatcher: '@Symfony\Contracts\EventDispatcher\EventDispatcherInterface'
        $options:
            namespace:    '%overblog_graphql.class_namespace%'
            config:       "%overblog_graphql_types.config%"
            casheDir:     "%overblog_graphql.cache_dir%"
            useClassMap:  "%overblog_graphql.use_classloader_listener%"
            cacheDir:     "%kernel.cache_dir%"
            cacheDirMask: "%overblog_graphql.cache_dir_permissions%"

class constructor:

public function __construct(TypeBuilder $typeBuilder, EventDispatcherInterface $eventDispatcher, array $options) 
{
    $this->typeBuilder = $typeBuilder;
    $this->eventDispatcher = $eventDispatcher;
    $this->options = new GeneratorOptions($options);
}

As you can see, the class has now only 3 dependencies. Parameters are combined into the $options array and passed into GeneratorOptions class which is just a DTO to avoid working with arrays. It destructures the array and creates a nice object with autocompletion. Also since properties are typed, there is no need to create getters/setters:

class GeneratorOptions
{
    public ?string $cacheDir;
    public int $cacheDirMask;
    public array $configs;
    public bool $useClassMap;
    public ?string $baseCacheDir;
    public string $classNamespace;

    public function __construct($options)
    {
        $this->classNamespace = $options['classNamespace'];
        $this->cacheDir       = $options['cacheDir'];
        $this->configs        = $options['config'];
        $this->useClassMap    = $options['useClassMap'] ?? true;
        $this->baseCacheDir   = $options['baseCacheDir'] ?? null;
        $this->cacheDirMask   = $options['cacheDirMask'] ?? (
            // Apply permission 0777 for default cache dir otherwise apply 0775.
            null === $options['cacheDir'] ? 0777 : 0775
        );
    }
}

All this would greatly reduce the size of TypeGenerator class to a couple of methods and if you need to access the options, you just call the options object and work with it:

$options = $typeGenerator->options;

$options->cacheDir;
$options->baseCacheDir;
// etc...

As another option the GeneratorOptions object could be passed to TypeGenerator and not instantiated in it's constructor.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions