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

Laravel Json Casted Laravel Package

novius/laravel-json-casted

Cast JSON columns in Laravel models with per-key casting. Define sub-key casts via a method or dedicated cast class; values are exposed as a Fluent object with proper types (e.g., Carbon dates). Supports PHP 8.2+ and Laravel 10+.

View on GitHub
Deep Wiki
Context7

Getting Started

Install via Composer:

composer require novius/laravel-json-casted

For IDE autocompletion (optional but recommended):

// config/laravel-ide-helper.php
'model_hooks' => [
    \Novius\LaravelJsonCasted\Hooks\ModelHasJsonWithCastsHook::class,
],

First Use Case: Cast a JSON field with nested sub-keys in an Eloquent model:

// In your model
protected $casts = [
    'metadata' => \Novius\LaravelJsonCasted\Services\JsonCasted::class.':getMetadataCasts',
];

public function getMetadataCasts(): array
{
    return [
        'published_at' => 'date:Y-m-d',
        'is_active'    => 'boolean',
    ];
}

// Usage
$post = Post::first();
$post->metadata->published_at; // Now a Carbon instance
$post->metadata->is_active;    // Now a boolean

Implementation Patterns

1. Method-Based Casting (Recommended for Model-Specific Logic)

// Model: Post.php
protected $casts = [
    'settings' => JsonCasted::class.':getSettingsCasts',
];

public function getSettingsCasts(): array
{
    return [
        'theme'       => 'string',
        'notifications' => 'array',
        'last_login'  => 'datetime',
    ];
}

Workflow:

  • Define casts in a dedicated method (get{FieldName}Casts).
  • Use Laravel’s native casting syntax (e.g., date:Y-m-d, boolean).
  • Access casted values via fluent syntax ($model->settings->last_login).

2. Class-Based Casting (Recommended for Reusable Logic)

// Cast: SettingsCast.php
namespace App\Casts;

use Novius\LaravelJsonCasted\Services\JsonCasted;

class SettingsCast extends JsonCasted
{
    protected static array $casts = [
        'theme'       => 'string',
        'notifications' => 'array',
        'last_login'  => 'datetime',
    ];
}

// Model: Post.php
protected $casts = [
    'settings' => \App\Casts\SettingsCast::class,
];

Workflow:

  • Encapsulate casting logic in a dedicated class.
  • Reuse the same cast across multiple models.
  • Extend JsonCasted to add custom casting logic if needed.

3. Integration with API Resources

// API Resource: PostResource.php
public function toArray($request)
{
    return [
        'id' => $this->resource->id,
        'title' => $this->resource->title,
        'settings' => $this->resource->settings, // Automatically casted
    ];
}

Tip: The package works seamlessly with Laravel’s API resources. No additional configuration is needed.

4. Dynamic Casting (Advanced)

// Model: Post.php
protected $casts = [
    'dynamic_data' => JsonCasted::class.':getDynamicCasts',
];

public function getDynamicCasts(): array
{
    $casts = [];
    if ($this->type === 'premium') {
        $casts['expiry_date'] = 'datetime';
    }
    return $casts;
}

Use Case: Dynamically define casts based on model attributes or business logic.

Gotchas and Tips

Pitfalls

  1. Fluent Syntax Conflicts:

    • If your JSON field is accessed as an array elsewhere (e.g., $model->extras['date']), the fluent syntax ($model->extras->date) will fail.
    • Fix: Ensure consistent access patterns across the codebase.
  2. Circular References:

    • JSON with circular references (e.g., self-referential objects) may cause infinite loops during casting.
    • Fix: Validate JSON structure before casting or use a try-catch block:
      try {
          $model->extras->nested_field;
      } catch (\Exception $e) {
          // Fallback to raw JSON
          $model->extras = json_decode($model->extras, true);
      }
      
  3. Database-Level Casting:

    • If your JSON column is cast to an array at the database level (e.g., PostgreSQL jsonb), the package may apply casting twice, leading to unexpected behavior.
    • Fix: Disable database-level casting or adjust the package’s logic to handle this case.
  4. AGPL License:

    • The AGPL-3.0 license requires open-sourcing proprietary code if the package is used in a proprietary application.
    • Fix: Evaluate alternatives (e.g., MIT-licensed packages) if AGPL compliance is a concern.

Debugging Tips

  1. Check Casted Values:

    • Use dd($model->extras) to inspect the casted structure. If values are not casted as expected, verify the $casts array in your model or cast class.
  2. Validate JSON:

    • Ensure the JSON field contains valid data before casting:
      if (json_validate($model->extras)) {
          $model->extras = json_decode($model->extras);
      }
      
  3. Override Default Casting:

    • Extend the JsonCasted class to customize behavior:
      class CustomJsonCasted extends JsonCasted
      {
          public function castUsing(array $casts, $value)
          {
              // Custom logic here
              return parent::castUsing($casts, $value);
          }
      }
      
  4. Performance Monitoring:

    • The fluent syntax adds minor overhead. Monitor performance in high-traffic applications:
      // Benchmark casting
      $start = microtime(true);
      $model->extras->nested_field;
      $time = microtime(true) - $start;
      

Extension Points

  1. Custom Casts:

    • Add support for custom cast types by extending the package:
      class CustomCast implements \Illuminate\Contracts\Database\Eloquent\CastsAttributes
      {
          public function get($model, string $key, $value, array $attributes)
          {
              // Custom casting logic
              return $value;
          }
      
          public function set($model, string $key, $value, array $attributes)
          {
              // Custom setting logic
              return $value;
          }
      }
      
    • Register the custom cast in your model’s $casts array.
  2. Global Casting:

    • Apply casting globally to all models using a trait or model observer:
      // AppServiceProvider.php
      Model::resolveCast('json_casted', function () {
          return \Novius\LaravelJsonCasted\Services\JsonCasted::class;
      });
      
  3. Fallback to Raw JSON:

    • Handle casting failures gracefully:
      public function getExtrasCasts(): array
      {
          return [
              'date' => 'date:Y-m-d',
              // Fallback to raw value if casting fails
              'fallback' => function ($value) {
                  return $value ?? null;
              },
          ];
      }
      
  4. IDE Helper Configuration:

    • Customize IDE helper behavior for better autocompletion:
      // config/laravel-ide-helper.php
      'model_hooks' => [
          \Novius\LaravelJsonCasted\Hooks\ModelHasJsonWithCastsHook::class,
          // Add other hooks as needed
      ],
      
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.
directorytree/privacy-filter-classifier
directorytree/privacy-filter
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
22h/doctrine-garbage-collection-bundle
agtp/agtp-php
agtp/mod-php
splash/sonata-admin
splash/metadata
splash/openapi
splash/scopes
splash/toolkit
testo/output-teamcity
testo/bridge-symfony
spatie/flare-daemon-runtime