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

Json Patch Php Laravel Package

mikemccabe/json-patch-php

PHP library implementing JSON Patch (RFC 6902) and JSON Pointer (RFC 6901). Diff two JSON documents, apply patch operations, or read values via pointers. Works with json_decode(..., true) arrays; includes optional SimpleXML-style array handling.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation: Add to composer.json:

    "require": {
        "mikemccabe/json-patch-php": "dev-master"
    }
    

    Run composer update.

  2. First Use Case: Apply a patch to a Laravel Eloquent model:

    use mikemccabe\JsonPatch\JsonPatch;
    
    $user = User::find(1);
    $userData = $user->toArray();
    $patches = [
        ['op' => 'replace', 'path' => '/name', 'value' => 'New Name'],
        ['op' => 'add', 'path' => '/metadata/updated', 'value' => true]
    ];
    $patchedData = JsonPatch::patch($userData, $patches);
    $user->update($patchedData);
    
  3. Key Entry Points:

    • Apply Patches: JsonPatch::patch($doc, $patches)
    • Generate Diffs: JsonPatch::diff($src, $dst)
    • Query Values: JsonPatch::get($doc, $pointer)

Implementation Patterns

Core Workflows

1. API Patch Endpoint

// routes/api.php
Route::patch('/users/{id}', [UserPatchController::class, 'update']);

// app/Http/Controllers/UserPatchController.php
public function update(Request $request, User $user) {
    $patches = json_decode($request->getContent(), true);
    $userData = $user->toArray();
    $patchedData = JsonPatch::patch($userData, $patches);
    $user->update($patchedData);
    return response()->json($patchedData);
}

2. Data Synchronization

Compare two Eloquent models and generate patches:

$source = User::find(1)->toArray();
$target = User::find(2)->toArray();
$patches = JsonPatch::diff($source, $target);
// Apply patches to source to match target

3. Simplexml Mode for XML-to-JSON

Enable for arrays from SimpleXML:

$simplexmlData = simplexml_load_string($xml)->jsonSerialize();
$patched = JsonPatch::patch($simplexmlData, $patches, true); // true = simplexml_mode

4. Validation Middleware

Ensure patches conform to RFC 6902:

// app/Http/Middleware/ValidatePatch.php
public function handle($request, Closure $next) {
    $patches = json_decode($request->getContent(), true);
    foreach ($patches as $patch) {
        if (!in_array($patch['op'], ['add', 'remove', 'replace', 'move', 'copy', 'test'])) {
            abort(400, 'Invalid patch operation');
        }
    }
    return $next($request);
}

Integration Tips

Laravel-Specific Patterns

  • Form Request Validation:

    // app/Http/Requests/PatchUserRequest.php
    public function rules() {
        return [
            '*.op' => 'required|in:add,remove,replace,move,copy,test',
            '*.path' => 'required|string',
        ];
    }
    
  • Service Layer Abstraction:

    // app/Services/PatchService.php
    class PatchService {
        public function apply(array $data, array $patches): array {
            return JsonPatch::patch($data, $patches);
        }
    }
    
  • Testing with Factories:

    // tests/Feature/PatchTest.php
    public function test_patch_user() {
        $user = User::factory()->create();
        $patches = [['op' => 'replace', 'path' => '/name', 'value' => 'Patched']];
        $patched = $this->patch("/users/{$user->id}", $patches);
        $patched->assertJson(['name' => 'Patched']);
    }
    

Performance Optimization

  • Batch Processing:

    // Process patches in chunks for large datasets
    $chunkSize = 100;
    $chunks = array_chunk($patches, $chunkSize);
    foreach ($chunks as $chunk) {
        $data = JsonPatch::patch($data, $chunk);
    }
    
  • Caching Diffs:

    // Cache patch diffs for expensive operations
    $cacheKey = "diff_{$sourceId}_{$targetId}";
    $patches = Cache::remember($cacheKey, now()->addHours(1), function() use ($source, $target) {
        return JsonPatch::diff($source, $target);
    });
    

Gotchas and Tips

Pitfalls

  1. PHP 8.x Compatibility:

    • Issue: Constructor properties or strict types may break.
    • Fix: Fork the repo and update JsonPatch class:
      // Before (PHP 5.6)
      public function __construct() { ... }
      
      // After (PHP 8.1)
      public function __construct(
          private bool $simplexmlMode = false
      ) { ... }
      
  2. Simplexml Mode Quirks:

    • Issue: Empty arrays [] vs. objects {} behave identically, causing unexpected add operations.
    • Fix: Normalize data before patching:
      $data = array_filter($data, fn($v) => $v !== null, ARRAY_FILTER_USE_BOTH);
      
  3. Circular References:

    • Issue: JSON Patch spec doesn’t handle circular references; may cause infinite loops.
    • Fix: Use json_encode() + json_decode() to flatten data:
      $flatData = json_decode(json_encode($data), true);
      
  4. Path Resolution:

    • Issue: /foo/0/bar may fail if /foo is not an array.
    • Fix: Validate paths before applying:
      $pointer = new \mikemccabe\JsonPointer\JsonPointer($patch['path']);
      if (!$pointer->get($data)) {
          throw new \InvalidArgumentException("Invalid path: {$patch['path']}");
      }
      
  5. Laravel-Specific Gotchas:

    • Issue: Eloquent casts (e.g., date, encrypted) may corrupt patched values.
    • Fix: Apply patches before casting:
      $attributes = $model->getAttributes();
      $patched = JsonPatch::patch($attributes, $patches);
      $model->setRawAttributes($patched);
      

Debugging Tips

  1. Validate Patches: Use the official test suite:

    git submodule update --init --recursive
    php runtests.php
    
  2. Log Patch Operations:

    // app/Services/PatchService.php
    public function apply(array $data, array $patches): array {
        $patched = JsonPatch::patch($data, $patches);
        \Log::debug('Applied patches', [
            'input' => $data,
            'patches' => $patches,
            'output' => $patched,
        ]);
        return $patched;
    }
    
  3. Inspect Pointers: Manually test JSON Pointers:

    $pointer = new \mikemccabe\JsonPointer\JsonPointer('/users/0/name');
    $value = $pointer->get($data);
    
  4. Handle Edge Cases:

    • Empty Arrays: Explicitly check for [] vs. {}.
    • Numeric Keys: Ensure /foo/0 vs. /foo/1 are handled as arrays.

Extension Points

  1. Custom Patch Operations: Extend the core logic:

    // app/Extensions/CustomPatch.php
    class CustomPatch extends \mikemccabe\JsonPatch\JsonPatch {
        public static function customOp($doc, $patch) {
            // Implement custom operation (e.g., 'increment')
            $pointer = new \mikemccabe\JsonPointer\JsonPointer($patch['path']);
            $value = $pointer->get($doc);
            $pointer->set($doc, $value + 1);
            return $doc;
        }
    }
    
  2. Laravel Event Integration: Trigger events after patching:

    // app/Listeners/PatchApplied.php
    public function handle($event) {
        event(new PatchApplied($event->model, $event->patches));
    }
    
  3. Policy Integration: Restrict patch operations:

    // app/Policies/UserPatchPolicy.php
    public function applyPatch(User $user, array $patches) {
        return $user->id === auth()->id();
    }
    
  4. Testing Utilities: Add helper methods to JsonPatch:

    // app/Extensions/TestHelpers.php
    namespace mikemccabe\JsonPatch;
    
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.
terminal42/code-quality-tools
codifyo/ts-generator-bundle
andydefer/laravel-cluster
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
christhompsontldr/laravel-inky