Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Fractal Laravel Package

php-open-source-saver/fractal

Fractal is a maintained fork of thephpleague/fractal for transforming complex data into consistent API output. Provides a presentation layer with transformers, type casting, relationship includes, custom serializers, and pagination support for JSON/YAML APIs.

View on GitHub
Deep Wiki
Context7
## Getting Started

### Minimal Setup
1. **Install the Package**:
   ```bash
   composer require php-open-source-saver/fractal

Replace League\Fractal with PHPOpenSourceSaver\Fractal in your codebase.

  1. First Use Case: Transform a Single Model Create a transformer for your Eloquent model (e.g., User):

    use PHPOpenSourceSaver\Fractal\TransformerAbstract;
    
    class UserTransformer extends TransformerAbstract
    {
        public function transform($user)
        {
            return [
                'id' => $user->id,
                'name' => $user->name,
                'email' => $user->email,
            ];
        }
    }
    
  2. Create a Resource and Serialize:

    use PHPOpenSourceSaver\Fractal\Manager;
    use PHPOpenSourceSaver\Fractal\Resource\Item;
    
    $manager = new Manager();
    $resource = new Item($user, new UserTransformer());
    $serializer = $manager->createData($resource)->toArray();
    
  3. Output JSON:

    return response()->json($serializer);
    

Where to Look First

  • Official Documentation (mirrored for this fork).
  • TransformerAbstract: Core class for defining how data is transformed.
  • Manager: Orchestrates the transformation process.
  • Resource\Item/Collection: Wraps data and transformers for serialization.

Implementation Patterns

1. Transformer Workflows

Single Resource Transformation

// Transformer for a single model (e.g., User)
class UserTransformer extends TransformerAbstract
{
    public function transform($user)
    {
        return [
            'id' => $user->id,
            'name' => $user->name,
            'email' => $user->email,
            'posts_count' => $user->posts()->count(), // Eager-loaded or lazy
        ];
    }

    // Include relationships (e.g., posts)
    public function includePosts($user)
    {
        return $this->collection($user->posts, new PostTransformer());
    }
}

Collection Transformation

// Transformer for a collection (e.g., Posts)
class PostTransformer extends TransformerAbstract
{
    public function transform($post)
    {
        return [
            'id' => $post->id,
            'title' => $post->title,
            'content' => $post->content,
        ];
    }
}

// Usage:
$posts = Post::all();
$resource = new Collection($posts, new PostTransformer());
$serializer = $manager->createData($resource)->toArray();

Nested Includes

Request relationships via URL (e.g., /users?include=posts.comments):

// In your controller:
$includes = $request->input('include', []);
$resource = new Item($user, new UserTransformer());
$resource->setIncludes($includes);
$serializer = $manager->createData($resource)->toArray();

2. Pagination Integration

Laravel Paginator

use PHPOpenSourceSaver\Fractal\Pagination\IlluminatePaginatorAdapter;

$paginator = Post::paginate(10);
$resource = new Collection($paginator->items(), new PostTransformer());
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
$serializer = $manager->createData($resource)->toArray();

Custom Paginator Adapters

For frameworks like Doctrine or Pagerfanta:

use PHPOpenSourceSaver\Fractal\Pagination\DoctrinePaginatorAdapter;

$doctrinePaginator = $entityManager->getRepository(Post::class)->findAll();
$adapter = new DoctrinePaginatorAdapter($doctrinePaginator);
$resource->setPaginator($adapter);

3. Serialization Formats

JSON:API Serializer

use PHPOpenSourceSaver\Fractal\Serializer\JsonApiSerializer;

$serializer = new JsonApiSerializer();
$manager->setSerializer($serializer);
$output = $manager->createData($resource)->toArray();

Output:

{
  "data": {
    "type": "users",
    "id": "1",
    "attributes": {
      "name": "John Doe",
      "email": "john@example.com"
    },
    "relationships": {
      "posts": {
        "data": [{"type": "posts", "id": "1"}]
      }
    }
  }
}

Array Serializer

use PHPOpenSourceSaver\Fractal\Serializer\ArraySerializer;

$serializer = new ArraySerializer();
$manager->setSerializer($serializer);
$output = $manager->createData($resource)->toArray();

Output:

{
  "data": {
    "id": 1,
    "name": "John Doe",
    "email": "john@example.com",
    "posts": [
      {"id": 1, "title": "First Post"}
    ]
  }
}

4. Fieldsets for Sparse Data

Limit fields returned via ?fields[users]=name,email:

// In your transformer:
public function getAvailableIncludes()
{
    return ['posts'];
}

public function getDefaultIncludes()
{
    return [];
}

public function getAvailableFields()
{
    return ['id', 'name', 'email']; // Only these fields can be requested
}

// In your controller:
$fields = $request->input('fields.users', ['id', 'name', 'email']);
$resource = new Item($user, new UserTransformer());
$resource->setFields($fields);
$serializer = $manager->createData($resource)->toArray();

5. Meta Data and Customization

Add metadata to responses:

$resource = new Item($user, new UserTransformer());
$resource->setMeta([
    'custom_field' => 'value',
    'timestamp' => now()->toIso8601String(),
]);

Override serializer links (e.g., for HAL):

$serializer = new ArraySerializer();
$serializer->setLinks([
    'self' => url()->current(),
    'next' => $resource->getPaginator()->getNextPageUrl(),
]);

Gotchas and Tips

Pitfalls

  1. Namespace Mismatch:

    • Error: Class 'League\Fractal\Manager' not found.
    • Fix: Replace all League\Fractal with PHPOpenSourceSaver\Fractal (see Migration Guide).
  2. Circular References:

    • Issue: Infinite loops when including bidirectional relationships (e.g., User->posts->user).
    • Fix: Use ->limit() or ->take() in relationships or implement a visited array in transformers:
      public function includePosts($user, $visited = [])
      {
          if (isset($visited[$user->id])) return null;
          $visited[$user->id] = true;
          return $this->collection($user->posts, new PostTransformer(), $visited);
      }
      
  3. Pagination Meta Conflicts:

    • Issue: Custom meta data overriding pagination metadata (e.g., links or meta keys).
    • Fix: Explicitly set pagination metadata in the adapter or use setMeta() after setting the paginator:
      $resource->setPaginator($adapter);
      $resource->setMeta(['custom' => 'value'], 'pagination'); // Target specific meta group
      
  4. Fieldset Parsing:

    • Issue: parseFieldsets() failing with malformed input.
    • Fix: Validate input in the controller:
      $fields = explode(',', $request->input('fields.users', ''));
      $resource->setFields(array_filter($fields));
      
  5. JSON:API ID Uniqueness:

    • Issue: Duplicate IDs in nested relationships (e.g., same post_id in comments).
    • Fix: Ensure your model’s getRouteKey() or getKey() returns a unique identifier.

Debugging Tips

  1. Inspect Transformed Data: Use toArray() before serialization to debug:

    $data = $manager->createData($resource)->toArray();
    dd($data); // Debug the output
    
  2. Log Includes: Add logging to parseIncludes() to verify relationship requests:

    $includes = $manager->parseIncludes($request->input('include'));
    \Log::debug('Includes parsed:', $includes->all());
    
  3. Serializer-Specific Quirks:

    • JSON:API: Ensure type and id are always present in nested resources.
    • ArraySerializer: Numeric keys in arrays may be reindexed; use ArraySerializer::setPreserveKeys(true) if needed.
  4. Performance:

    • **N
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
ilhamsyabani/laravel-volt-starter
thethunderturner/filament-latex
ghostcompiler/laravel-querybuilder
webrek/laravel-telescope-mongodb
anousss007/blatui
zatona-eg/zatona-eg-api
cocosmos/filament-sticky-save-bar
patrickbussmann/oauth2-apple
3brs/enterprise-security-bundle
anousss007/vigilance
supportpal/eloquent-model
ardenexal/fhir-models
laravel-at/laravel-image-sanitize
romalytar/yammi-audit-log-laravel
ardenexal/fhir-validation
arshaviras/weather-widget
laravel-chronicle/core
sunchayn/nimbus
daikazu/eloquent-salesforce-objects
unseen-codes/chat