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

Hal Laravel Package

nocarrier/hal

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require nocarrier/hal
    

    Add to composer.json if not using autoload globally:

    "autoload": {
        "psr-4": {
            "App\\": "app/",
            "Nocarrier\\": "vendor/nocarrier/hal/src/"
        }
    }
    

    Run composer dump-autoload.

  2. First Use Case: Create a simple HAL resource in a Laravel controller:

    use Nocarrier\Hal;
    
    public function showOrder(Order $order)
    {
        $resource = new Hal('/api/orders/' . $order->id, [
            'id' => $order->id,
            'amount' => $order->amount,
            'status' => $order->status,
        ]);
    
        $resource->addLink('self', '/api/orders/' . $order->id);
        $resource->addLink('customer', '/api/customers/' . $order->user_id);
    
        return response()->json($resource->asJson());
    }
    
  3. Key Starting Points:

    • Hal class constructor takes URI and data array.
    • Use addLink() for relationships (e.g., self, collection, up).
    • Embed resources with addResource() for nested HAL documents.
    • Output with asJson() or asXml().

Implementation Patterns

Common Workflows

1. API Resource Transformation

Use HAL to standardize API responses with hypermedia controls:

public function index()
{
    $collection = new Hal('/api/orders', [], 'orders');
    foreach ($orders as $order) {
        $resource = new Hal('/api/orders/' . $order->id, [
            'id' => $order->id,
            'amount' => $order->amount,
        ]);
        $resource->addLink('self', '/api/orders/' . $order->id);
        $collection->addResource('order', $resource);
    }
    return response()->json($collection->asJson());
}

2. Dynamic Link Generation

Generate links dynamically in controllers or services:

$resource->addLink('edit', route('admin.orders.edit', $order->id));
$resource->addLink('delete', route('admin.orders.destroy', $order->id), [
    'method' => 'DELETE',
    'title' => 'Delete Order',
]);

3. Embedding Related Resources

Fetch and embed related models (e.g., customer for an order):

$orderResource = new Hal('/api/orders/' . $order->id, [...]);
$customerResource = new Hal('/api/customers/' . $order->user_id, [
    'name' => $order->user->name,
]);
$orderResource->addResource('customer', $customerResource);

4. Middleware for HAL Responses

Create middleware to wrap responses in HAL format:

public function handle($request, Closure $next)
{
    $response = $next($request);
    if ($response->isJson()) {
        $data = $response->json();
        $hal = new Hal($request->url(), $data);
        $response->setContent($hal->asJson());
    }
    return $response;
}

5. Formatting with Laravel's Resource Classes

Combine with Laravel's JsonResource for cleaner code:

public function toArray($request)
{
    return [
        'id' => $this->id,
        'amount' => $this->amount,
        '_links' => [
            'self' => ['href' => route('api.orders.show', $this)],
        ],
    ];
}

Then convert to HAL in the controller:

$resource = new Hal('/api/orders/' . $order->id, $order->toArray($request));

Integration Tips

Laravel Service Providers

Bind HAL to the container for dependency injection:

public function register()
{
    $this->app->bind(Hal::class, function () {
        return new Hal('/');
    });
}

API Versioning

Use HAL to include versioned links:

$resource->addLink('self', '/v1/orders/' . $order->id);
$resource->addLink('latest', '/v2/orders/' . $order->id);

Caching HAL Responses

Cache HAL-formatted responses in Laravel:

return Cache::remember("hal.order.{$order->id}", now()->addHours(1), function () use ($order) {
    return response()->json((new Hal(...))->asJson());
});

Testing

Test HAL responses with PHPUnit:

public function testHalResponse()
{
    $response = $this->get('/api/orders/1');
    $hal = json_decode($response->getContent(), true);
    $this->assertArrayHasKey('_links', $hal);
    $this->assertArrayHasKey('self', $hal['_links']);
}

Gotchas and Tips

Pitfalls

1. URI Normalization

  • HAL expects absolute URIs (e.g., /api/orders/1). Relative paths (e.g., ../orders/1) may break links.
  • Fix: Use Laravel's url() or route() helpers to generate absolute paths:
    $resource->addLink('self', url('/api/orders/' . $order->id));
    

2. Link Href vs. Title Confusion

  • addLink() accepts href and title as separate parameters, but the method signature might be confusing:
    // Correct:
    $resource->addLink('self', '/url', ['title' => 'Order Details']);
    
    // Incorrect (will throw error):
    $resource->addLink('self', ['href' => '/url', 'title' => 'Order Details']);
    

3. Nested Resource Overwriting

  • If you add the same resource key twice (e.g., addResource('customer', ...)), the last one wins.
  • Fix: Use unique keys or merge resources carefully.

4. XML Output Quirks

  • The asXml() method may not handle all edge cases (e.g., special characters in data).
  • Fix: Sanitize data before passing to HAL or use htmlspecialchars():
    $data['description'] = htmlspecialchars($order->description);
    

5. Performance with Large Collections

  • Embedding many resources (e.g., 1000+ orders) can bloat the response.
  • Fix: Use pagination or lazy-loading:
    $collection->addResource('order', $resource); // Only add current page's orders
    

Debugging Tips

1. Validate HAL Structure

Use online validators like HAL Explorer to check your output:

// Dump raw HAL for debugging:
dd($resource->asJson());

2. Check for Missing Links

Ensure _links are always included in responses:

if (!isset($hal['_links'])) {
    throw new \RuntimeException('HAL document missing _links section.');
}

3. Log HAL Output

Log HAL responses for debugging:

\Log::debug('HAL Response', [
    'uri' => $resource->getUri(),
    'data' => $resource->asJson(),
]);

Extension Points

1. Custom Link Types

Extend HAL to support custom link relations (e.g., api:update):

$resource->addLink('api:update', '/api/orders/' . $order->id, [
    'method' => 'PATCH',
    'title' => 'Update Order',
]);

2. Add Metadata

Include custom metadata in the _meta section:

$resource->setMeta(['created_at' => $order->created_at->toIsoString()]);

3. Override Serialization

Extend the Hal class to customize JSON/XML output:

class CustomHal extends Hal
{
    public function asJson()
    {
        $json = parent::asJson();
        // Modify $json here (e.g., add timestamps)
        return $json;
    }
}

4. Integrate with Laravel Policies

Use HAL to expose policy-based links:

if ($this->authorize('update', $order)) {
    $resource->addLink('update', route('api.orders.update', $order));
}

5. Add CORS Headers

Combine HAL with CORS middleware:

$response = response()->json($
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.
besmartand-pro/php-quality-config
sentix/ai-chatbot
terminal42/code-quality-tools
codifyo/ts-generator-bundle
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity