[Suggestion] Use a container to fetch transformers
hubertnnn opened this issue · comments
Currently fractal requires transformer to be an object.
So your code will look like this:
$fractal = new Manager();
$array = $fractal->createData(new Collection($books, new BookTransformer))->toArray();
// and
public function includeAuthor(Book $book)
{
return $this->item($book->author, new AuthorTransformer);
}
This may not work well with some frameworks (eg. Symfony),
since its possible that a transformer might have extra dependencies (eg. Translator).
Passing those dependencies between transformers is difficult and error prone,
so it would be much better to have a way to fetch transformers from a container.
The solution could be as simple as:
$fractal = new Manager();
$fractal->setContainer($container);
$array = $fractal->createData(new Collection($books, BookTransformer::class))->toArray();
// and
public function includeAuthor(Book $book)
{
return $this->item($book->author, AuthorTransformer::class);
}
By default fractal could use a dummy container that just calls a constructor:
class ConstructionContainer implements \Psr\Container\ContainerInterface
{
public function has(string $class)
{
return class_exists($class);
}
public function get(string $class)
{
return new new $class();
}
}
This way if you provide a callable or object as $transformer
then behavior will not change.
But if you provide a string, the transformer object will be fetched from the container.
There's nothing stopping you from using a container to build your transformers today
class BookTransformer
{
public function __construct(
protected AuthorTransformer $authorTransformer,
) {}
...
public function includeAuthor(Book $book)
{
return $this->item($book->getAuthor(), $this->authorTransformer);
}
}
In my opinion this is a better way to go about things since you end up with explicit dependencies rather than implicit service locator based dependencies that can be much harder to test.