dmytrof / fractal-bundle
Symfony FractalBundle
Installs: 6 417
Dependents: 1
Suggesters: 0
Security: 0
Stars: 0
Watchers: 1
Forks: 1
Open Issues: 0
Type:symfony-bundle
pkg:composer/dmytrof/fractal-bundle
Requires
- php: ^7.2 || ^8.0
- ext-json: *
- doctrine/collections: ^1.6
- league/fractal: ^0.18
- symfony/framework-bundle: ^3.4 || ^4.3 || ^5.0
Requires (Dev)
- friendsofsymfony/rest-bundle: ^2.2 || ^3.0
- phpunit/phpunit: ^8.3 || ^9.1
Suggests
- friendsofsymfony/rest-bundle: Adds support for using Fractal with FOSRestBundle
- league/fractal: Allows more advanced using of Fractal
README
This bundle helps you to implement Fractal by League into your Symfony 3/4/5 application
Installation
Step 1: Install the bundle
$ composer require dmytrof/fractal-bundle 
Step 2: Enable the bundle
Symfony 3:
<?php
// app/AppKernel.php
public function registerBundles()
{
    $bundles = array(
        // ...
        new Dmytrof\FractalBundle\DmytrofFractalBundle(),
        // ...
    );
}
Symfony 4/5:
<?php
    // config/bundles.php
    
    return [
        // ...
        Dmytrof\FractalBundle\DmytrofFractalBundle::class => ['all' => true],
    ];
Usage
Read the official Fractal documentation before using this bundle
1.Basic usage
Imagine you have some models Article:
<?php
namespace App\Model;
use App\Model\Author;
class Article
{
    /**
     * @var int
     */
    protected $id;
    /**
     * @var Author
     */
    protected $author;
    /**
     * @var string
     */
    protected $title;
    /**
     * @var string
     */
    protected $body;
    /**
     * @var \DateTime
     */
    protected $publishedAt;
    /**
     * Returns id
     * @return int|null
     */
    public function getId(): ?int
    {
        return $this->id;
    }
    /**
     * Sets id
     * @param int|null $id
     * @return $this
     */
    public function setId(?int $id): Article
    {
        $this->id = $id;
        return $this;
    }
    /**
     * Returns author
     * @return Author|null
     */
    public function getAuthor(): ?Author
    {
        return $this->author;
    }
    /**
     * Sets author
     * @param Author|null $author
     * @return Article
     */
    public function setAuthor(?Author $author): Article
    {
        $this->author = $author;
        return $this;
    }
    // ...
    // Other Setters and Getters
    // ...
    /**
     * Returns published at date
     * @return \DateTime|null
     */
    public function getPublishedAt(): ?\DateTime
    {
        return $this->publishedAt;
    }
    /**
     * Sets published at date
     * @param \DateTime|null $publishedAt
     * @return Article
     */
    public function setPublishedAt(?\DateTime $publishedAt): Article
    {
        $this->publishedAt = $publishedAt;
        return $this;
    }
}
and Author:
<?php
namespace App\Model;
class Author
{
    /**
     * @var int
     */
    protected $id;
    /**
     * @var string
     */
    protected $firstName;
    /**
     * @var string
     */
    protected $lastName;
    /**
     * @var string
     */
    protected $email;
    /**
     * Returns id
     * @return int|null
     */
    public function getId(): ?int
    {
        return $this->id;
    }
    /**
     * Sets id
     * @param int|null $id
     * @return Author
     */
    public function setId(?int $id): Author
    {
        $this->id = $id;
        return $this;
    }
    // ...
    // Other Getters and Setters
    // ...
}
Create transformers for your entities
AuthorTransformer:
<?php
namespace App\FractalTransformer;
use App\Model\Author;
use Dmytrof\FractalBundle\Transformer\AbstractTransformer;
class AuthorTransformer extends AbstractTransformer
{
    // Model which is handled by this transformer
    protected const SUBJECT_CLASS = Author::class;
    /**
     * @var bool
     */
    protected $showShortInfo = false;
    /**
     * @return bool
     */
    public function isShowShortInfo(): bool
    {
        return $this->showShortInfo;
    }
    /**
     * Sets show short info
     * @param bool $showShortInfo
     * @return AuthorTransformer
     */
    public function setShowShortInfo(bool $showShortInfo = true): AuthorTransformer
    {
        $this->showShortInfo = $showShortInfo;
        return $this;
    }
    /**
     * Transforms Author to array
     * @param Author $subject
     * @return array
     */
    public function transformSubject($subject): array
    {
        $data = [
            'id' => $subject->getId(),
            'firstName' => $subject->getFirstName(),
            'lastName' => $this->isShowShortInfo() ? substr($subject->getLastName(), 0, 1).'.' : $subject->getLastName(),
        ];
        if (!$this->isShowShortInfo()) {
            $data['email'] = $subject->getEmail();
        }
        return $data;
    }
}
and ArticleTransformer:
<?php
namespace App\FractalTransformer;
use App\Model\Article;
use Dmytrof\FractalBundle\Transformer\AbstractTransformer;
use League\Fractal\Resource\{Item, ResourceInterface};
class ArticleTransformer extends AbstractTransformer
{
    // Model which is handled by this transformer
    protected const SUBJECT_CLASS = Article::class;
    protected $defaultIncludes = [
        'author'
    ];
    protected $availableIncludes = [
        'body',
    ];
    /**
     * Transforms Article to array
     * @param Article $subject
     * @return array
     */
    public function transformSubject($subject): array
    {
        return [
            'id' => $subject->getId(),
            'title' => $subject->getTitle(),
            'publishedAt' => $this->transformDateTime($subject->getPublishedAt()),
        ];
    }
    /**
     * Includes author
     * @param Article $article
     * @return Item
     */
    public function includeAuthor(Article $article): Item
    {
        return $this->item($article->getAuthor(), AuthorTransformer::class);
    }
    /**
     * Includes body
     * @param Article $article
     * @return ResourceInterface
     */
    public function includeBody(Article $article): ResourceInterface
    {
        return $this->primitive($article->getBody());
    }
}
Update controller
<?php
namespace App\Controller\Api\v1;
use App\Model\Article;
use App\FractalTransformer\ArticleTransformer;
use Dmytrof\FractalBundle\Service\FractalManager;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\HttpFoundation\{Request, JsonResponse};
/**
 * @Route("/api/v2/articles")
 */
class ArticleController extends AbstractController
{
    /**
     * @Route("/{id<\d+>}", methods={"GET"})
     */
    public function getOne(int $id, Request $request, FractalManager $fractalManager)
    {
        $model = $this->getArticeById($id); // Some method to receive model
        
        $fractalManager
            ->parseIncludes($request->get('include', ''))
            ->parseExcludes($request->get('exclude', ''))
            ->parseFieldsets($request->get('fieldsets', []))
        ;
        return new JsonResponse([
            'data' => $fractalManager->getModelData($model, ArticleTransformer::class),
        ], JsonResponse::HTTP_OK);
    }
}