This forum has moved to a new location and is in read-only mode. Please visit talk.octobercms.com to access the new location.

ivan_g
ivan_g

Hi guys,

In my first under-construction project using octobercms I have created a custom plugin to manage events. With the help of the cool "builder" plugin I successfully create and update items with lists and forms in the backend (models, controllers, menu and so on, are all working correctly).

Now I'd need to add a command to duplicate/clone a single event (when I'm updating it or from the list view). I would simply store a copy of the selected/opened record with a new id probably, but have no idea of how add a feature like this in the controllers of the plugin.

Normally in a typical laravel project I write a function in the controller, called via ajax and passing the id, and then using the model I clone and save the item... but with October I have not yet enough knowledgment to do something like this...

Are there any ideas and help out there please? thanks so much, Ivan

Last updated

ivan_g
ivan_g

ok I got it... not so difficult indeed ;-)

[here it is a reference:]https://octobercms.com/docs/backend/controllers-ajax

first of all I added a button in the _list_toolbar.htm (under controllers) of this kind, where the most important point is the data-request param:

    <button
        class="btn btn-default oc-icon-clone"
        disabled="disabled"
        onclick="$(this).data('request-data', {
            checked: $('.control-list').listWidget('getChecked')
        })"
        data-request="onDuplicate"
        data-request-confirm="Do you wanna duplicate this event?"
        data-trigger-action="enable"
        data-trigger=".control-list input[type=checkbox]"
        data-trigger-condition="checked"
        data-request-success="$(this).prop('disabled', true)"
        data-stripe-load-indicator>
        Duplicate selected
    </button>

then in the controller php file I define the function assigned to this button with something like this:

    public function onDuplicate() {
           $checked_items_ids = input('checked');

           foreach ($checked_items_ids as $id) {
              $original = Event::where("id", $id)->first();

              $clone = $original->replicate();
              $clone->title = "CPY ".$clone->title;
              $clone->slug = now()->timestamp."_".$clone->slug;
              $clone->published = 0;
              $clone->highlight = 0;
              $fake = new \System\Models\File;
              $imgs = $original->gallery;
              $fake->fromUrl($imgs[0]->getPath(), now()->timestamp.'.jpg');      
              $clone->id = Event::withTrashed()->max('id') + 1;
              $clone->gallery()->add($fake);

              $clone->save();
           }

           \Flash::success('Event cloned');
           return $this->listRefresh();
    }  

note that the gallery is required in my project, so I have to create a clone also of the first image at least... another point is about the 'withTrashed" because I'm using softdelete. And finally the listRefresh redraws the list in the view and I can see, open and edit the duplicated event. Cool isn't it? :smirk:

Thanks Octobercms, I'm really enjoying using it!

docu2931641
docu2931641

Hello! Thanks for the solution you posted. I was looking for something like that. Do you know how to copy the translation of an article's content when using the Translate plugin? Thank you!

VasekS
VasekS

Hello, may i ask you, i was tried your scrtipt, but after confirm script return message:

Method [where] does not exist on [Ipw\webcontent\Controllers\Projects]." on line 68 of /www/doc/devel.site.cz/www/vendor/laravel/framework/src/Illuminate/Routing/Controller.php

do you have any idea how to fix it?

ipw/webcontent/controllers/Projects.php

namespace Ipw\webcontent\Controllers;
use Backend\Classes\Controller;
use BackendMenu;
class Projects extends Controller
{
public $implement = [        'Backend\Behaviors\ListController',        'Backend\Behaviors\FormController',        'Backend\Behaviors\ReorderController'    ];

public $listConfig = 'config_list.yaml';
public $formConfig = 'config_form.yaml';
public $reorderConfig = 'config_reorder.yaml';

public function __construct()
{
    parent::__construct();
    BackendMenu::setContext('Ipw.webcontent', 'main-menu-projects');
}

public function onDuplicate() {

           $checked_items_ids = input('checked');  

           foreach ($checked_items_ids as $id) {

              $original = Projects::where("id", $id)->first();

              $clone = $original->replicate();
              $clone->title_cz = "CPY ".$clone->title_cz;
              $clone->enable = 0;  
              $clone->id = Projects::withTrashed()->max('id') + 1;

              $clone->save();

           }

           \Flash::success('Record cloned');
           return $this->listRefresh();
     } 
}

thank you

Vaclav

ivan_g
ivan_g

Hi, it seems that "Projects" it's not a laravel collection, so you can't use the method "where". Instead it's the name of the class that extends the main class controller. I think you have to import the correct model at the head (with the "use") and then should work.

VasekS
VasekS

Hi, thanks,

when i use in head

use Ipw\webcontent\Models\Projects;

script return message

Cannot declare class Ipw\webcontent\Controllers\Projects because the name is already in use

but this works

$original =  \Ipw\webcontent\Models\Projects::where("id", $id)->first();

thanks

Vaclav

icstudio
icstudio

samal.es said:

Hi, thanks,

when i use in head

use Ipw\webcontent\Models\Projects;

script return message

Cannot declare class Ipw\webcontent\Controllers\Projects because the name is already in use

but this works

$original = \Ipw\webcontent\Models\Projects::where("id", $id)->first();

thanks

Vaclav

It happen because you are trying to use Model with name Project inside Controller with name Project. To avoid this you can use 'as' for your model like this <code> use Ipw\webcontent\Models\Projects as ProjectsModel; </code> and this code: <code> $original = \Ipw\webcontent\Models\Projects::where("id", $id)->first(); </code> turn into this <code> $original = ProjectsModel::where("id", $id)->first(); </code>

icstudio
icstudio

samal.es said:

Hi, thanks,

when i use in head

use Ipw\webcontent\Models\Projects;

script return message

Cannot declare class Ipw\webcontent\Controllers\Projects because the name is already in use

but this works

$original = \Ipw\webcontent\Models\Projects::where("id", $id)->first();

thanks

Vaclav

It happen because you are trying to use Model with name Project inside Controller with name Project. To avoid this you can use 'as' for your model like this

use Ipw\webcontent\Models\Projects as ProjectsModel;

and this code:

$original = \Ipw\webcontent\Models\Projects::where("id", $id)->first();

turn into this

$original = ProjectsModel::where("id", $id)->first();

blaz
blaz

In case you need to duplicate attachment files, here is an example for attachOne and attachMany:

`public function onDuplicate() { $checked_items_ids = input('checked');

    $images = array_merge(
        array_keys((new YourModel())->attachOne),
        array_keys((new YourModel())->attachMany)
    );

    foreach ($checked_items_ids as $id) {
        $original = YourModel::where("id", $id)->with($images)->first();

        $clone = $original->replicate();

        $clone->sort_order = null;
        $clone->date_end = null;
        $clone->finished = 0;
        $clone->created_at = Carbon::now();
        $clone->updated_at = Carbon::now();

        $clone->save();

        $this->cloneImages($clone, $original, $images);
    }

    Flash::success('Auction cloned');
    return $this->listRefresh();
}

private function cloneImages(Auction $clone, Auction $original, array $images)
{
    foreach ($images as $image) {
        $fileModel = new \System\Models\File;
        $temp = $original->{$image};

        if (is_null($temp)) {
            continue;
        }

        if (is_a($temp, Collection::class)) {
            $temp->each(function($item) use ($image, $clone) {
                $fileModel = new \System\Models\File;
                $clone->{$image}()->save($fileModel->fromFile($item->getLocalPath()));
            });
        } else {
            $clone->{$image}()->save($fileModel->fromFile($temp->getLocalPath()));
        }
    }

    return $clone;
}

`

Depends on your use case. You can put this into queue to speed up processing for the end-users.

Last updated

1-9 of 9

You cannot edit posts or make replies: the forum has moved to talk.octobercms.com.