Weave 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

Copy Clone Laravel Package

tanvirofficials/copy-clone

A Laravel package for copying or cloning Eloquent models and their relationships. It helps duplicate records quickly with configurable options, making it useful for templates, drafts, repeated data entry, and admin workflows.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and register

composer require tanvirofficials/copy-clone

This is a Nova package, so the first place to look is app/Nova/NovaServiceProvider.php — check whether the package ships an auto-discovered service provider, and whether it registers a global action or expects you to add an action class per-resource. Read the repo README before writing any code; at 7 stars and a single 2021-era release, the docs are the only real spec you have.

Where to look first

  1. The README's install snippet and any published config (php artisan vendor:publish --tag=...).
  2. vendor/tanvirofficials/copy-clone/src/ — confirm the actual action class name, whether it clones relations, and whether it uses a trait or a handle()-based Nova Action.
  3. Your Nova version. The last release is Oct 2021, which lines up with the Nova 3.x action API. Nova 4/5 changed Action signatures, so verify compatibility before committing to it in a project.

First use case

The natural fit is admin-side "duplicate this record" on a detail or index page — e.g. cloning a Product so an ops user can spin up a variant without re-entering 30 fields, or cloning a CMS Page with its content blocks. Wire it up on one low-risk resource first, clone a record in staging, and inspect the resulting rows before rolling it out.

Start with a resource that has no unique indexes beyond the primary key and no side-effecting observers. That gives you a clean read on what the package actually copies.

Implementation Patterns

Attach the action to a resource

Nova actions are registered per-resource in actions(Request $request). Add the package's action alongside your own:

public function actions(Request $request)
{
    return [
        (new CloneRecord)->onlyOnDetail(),
    ];
}

Use onlyOnDetail() for cloning (index/bulk cloning is a footgun — see Gotchas). If you want it everywhere, register it as a global action in NovaServiceProvider::actions() instead, but prefer per-resource so you can tune it.

Normalize the clone in a subclass

Don't call the package action directly from ten resources. Wrap it once so behavior is consistent:

class CloneProduct extends CloneRecord
{
    public function handle(ActionFields $fields, Collection $models)
    {
        foreach ($models as $model) {
            DB::transaction(function () use ($model) {
                $copy = parent::handle(...); // or replicate manually
                $copy->forceFill([
                    'slug' => $model->slug . '-copy-' . Str::random(4),
                    'status' => 'draft',
                ])->save();
            });
        }
    }
}

If the package doesn't expose a clean extension seam, fall back to $model->replicate() plus explicit relation copying — you keep full control and lose nothing but the button.

Reset fields that must not be inherited

The day-to-day pattern is: clone everything, then scrub. Typical candidates are slugs, SKUs, external IDs, published timestamps, is_default flags, and any "current version" pointer. Centralize this in a cloneExcludedAttributes() method on the model or a small config map so it isn't re-derived per resource.

Handle relations explicitly

If the package recurses into relations, confirm which ones (hasMany? belongsToMany with pivot data? morphMany?). If it doesn't, do it yourself and always inside DB::transaction:

$copy = $original->replicate();
$copy->push();

foreach ($original->variants as $variant) {
    $copy->variants()->create($variant->only($variant->getFillable()));
}

Gate it

Cloning bypasses the normal create flow, so audit trails and "who created this" logic can be wrong. Restrict with ->canSee(fn () => $request->user()->isAdmin()) and make sure the clone records the acting user, not the original creator.

Queue the heavy ones

For resources with large child graphs (a template with 200 blocks), make the action ->queued() or dispatch your own job. Cloning in-request is fine for a handful of rows and painful beyond that.

Gotchas and Tips

  • Maturity risk is the headline. One release, 2021, 7 stars, zero dependents. Pin the exact version in composer.json, read the source before trusting it, and budget for a fork or a hand-rolled replicate() if it breaks. Do not adopt this in a codebase where you can't vendor the logic yourself.
  • Nova version drift. The action API changed between Nova 3 and 4/5. Test the clone on staging with your actual Nova version before wiring it into production resources; a silently-no-op action is worse than none.
  • Unique constraints are the #1 failure. A cloned sku, slug, email, or composite unique index throws a QueryException mid-transaction. Decide on a suffixing/blanking convention up front and apply it in one place.
  • Model events fire. replicate() and create() both trigger creating/created/saved, so observers that send mail, push to search indexes, or write audit rows will run for a clone. Use withoutEvents() if the clone shouldn't look like a real user action, or knowingly accept the side effects.
  • Files and media are usually not copied. Uploaded attachments, Spatie MediaLibrary items, and S3 paths typically stay attached to the original or vanish entirely. Verify this explicitly — it's the most common post-launch surprise with clone packages.
  • Pivot data. belongsToMany relations often get the relation rows but lose extra pivot columns (ordering, flags, timestamps on the pivot). Check ->withPivot() columns survive.
  • Soft deletes and timestamps. A clone should almost always be deleted_at = null and get fresh created_at. If the package copies raw attribute arrays, it may carry these over — override them.
  • Bulk cloning from the index multiplies every problem above by N and often times out. Prefer onlyOnDetail() until you've proven the action is safe.
  • Debugging: wrap the clone in DB::listen() or enable query logging and inspect what SQL the action emits; run it against a RefreshDatabase test that asserts row counts on parent and each child relation. That test is your regression guard when a Nova upgrade lands.
  • Extension points to check for: whether the action exposes a config file, a handle() you can override, or an event you can hook. If none exist, subclassing the action and calling parent::handle() is usually still viable — but confirm the method signature matches the signature of the method that's actually shipped.
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.
adachsoft/changelog-linter
adachsoft/collection
payerurl/telegrambot-crypto-payment-instant-payout
dskripchenko/laravel-hybrid-search
riorizkyrainey/lara-ced
mehedimi/static-vel
zharp/zharp
nonsapiens/bigquery-model-sync
lgu-bayambang-ict-office/lgu-laravel-development-standards
andydefer/laravel-support
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel
draftsmaninc/draftsman
square-bit/laravel-volition
himito/laravel-mailman
htinlynn/genius-helper
maco-studios/hephaestus
adachsoft/php-code-style