This forum has moved to a new location and is in read-only mode. Please visit talk.octobercms.com to access the new location.
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
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!
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!
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
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.
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
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>
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();
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