Installation:
composer require czim/laravel-nestedupdater
Publish the config (if needed):
php artisan vendor:publish --provider="Czim\NestedUpdater\NestedUpdaterServiceProvider"
Basic Usage:
use Czim\NestedUpdater\Facades\NestedUpdater;
$post = Post::find(1);
$data = [
'title' => 'Updated Title',
'comments' => [
17, // Keep existing comment with ID 17
['id' => 18, 'body' => 'Updated'], // Update existing comment
['body' => 'New comment'] // Create new comment
]
];
NestedUpdater::update($post, $data);
First Use Case:
Post) with nested relations (e.g., comments, tags, authors).Define Relationships:
Ensure your model uses standard Eloquent relationships (e.g., hasMany, belongsToMany).
class Post extends Model {
public function comments() { return $this->hasMany(Comment::class); }
public function tags() { return $this->belongsToMany(Tag::class); }
}
Update Structure: Pass an array where:
null (delete).
$data = [
'title' => 'New Title',
'comments' => [1, 2, ['body' => 'New'], null], // Keep 1,2; update new; delete null
'tags' => [1, 3, 5] // Sync tags (add/remove)
];
Bulk Operations:
Use updateMany() for multiple models:
$posts = Post::where('published', false)->get();
NestedUpdater::updateMany($posts, $data);
Custom Callbacks: Attach callbacks for pre/post-update logic:
NestedUpdater::update($post, $data, function ($model, $relation, $data) {
if ($relation === 'comments') {
// Custom logic for comments
}
});
/posts/1 with comments payload).Validator::make($data, [...])).updating/updated events for side effects (e.g., notifications).Circular References:
Avoid infinite loops if relations reference each other (e.g., Post ↔ Author ↔ Post).
Fix: Explicitly exclude problematic relations in config:
'exclude_relations' => ['authors.posts'],
Mass Assignment:
Ensure nested models have $fillable set or use updateOrCreate with guarded attributes.
Fix: Whitelist attributes in config:
'allowed_attributes' => ['comments.*' => ['body', 'status']],
Performance:
Deeply nested updates may trigger N+1 queries.
Fix: Use with() to eager-load relations:
$post = Post::with('comments.author')->find(1);
ID Conflicts:
Passing duplicate IDs (e.g., [1, 1, 2]) may cause unexpected behavior.
Fix: Normalize input arrays or use array_unique().
Log Updates: Enable debug mode in config:
'debug' => true,
Logs will show executed queries and skipped operations.
Dry Run:
Use NestedUpdater::dryRun($model, $data) to preview changes without saving.
Custom Updaters: Override the default updater for specific relations:
NestedUpdater::extend('comments', function ($model, $relation, $data) {
// Custom logic for comments
});
Model Events: Trigger events for nested updates:
NestedUpdater::onUpdating(function ($model, $data) {
event(new NestedUpdateStarting($model, $data));
});
Conditional Updates: Skip updates based on conditions:
NestedUpdater::update($post, $data, function ($model, $relation, $data) {
if ($relation === 'tags' && !$model->isAdmin) {
return false; // Skip tags for non-admins
}
});
Soft Deletes: Configure soft-delete behavior for nested models:
'soft_deletes' => [
'comments' => true, // Soft delete instead of hard delete
],
How can I help you explore Laravel packages today?