Preventing delete from draft if a live version is present?

105 views
Skip to first unread message

Patrick Nelson

unread,
Jun 12, 2015, 6:24:41 PM6/12/15
to silverst...@googlegroups.com
Is there a method by which I could prevent some user from accidentally deleting a draft version of a data object? I noticed that some issues were cropping up in our CMS where the user accidentally deleted the draft version but was unable to remove it from the production version of the site, because HasManyList relations will only return data retrieved from the draft (non suffixed) table. 

That or maybe have a way to join both tables (outer join, grouping by ID) so that I know I can at least return all versions of the page (preferring draft) in a SS_List instance (HasManyList in this case) and let the user REALLY delete the thing instead of having it lingering on forever without having to rip it out of the database guts manually via phpMyAdmin or something else just as ghastly? 

- Patrick

Patrick Nelson

unread,
Jun 12, 2015, 6:25:47 PM6/12/15
to silverst...@googlegroups.com
And by the way, I'm aware (at least in 3.1) that the ORM is limited in its capacity to join tables by doing only inner/left joins (naturally with the draft table being on the left) so that may be out of the question; unless I switch the table order and do some major under the hood stuff. Just not sure and pretty intimidated by the prospect of solving this problem.

Christopher Pitt

unread,
Jun 12, 2015, 6:53:45 PM6/12/15
to silverst...@googlegroups.com
The delete actions got some love for 3.2. Might be just what you need...

Patrick Nelson

unread,
Jun 25, 2015, 2:55:20 PM6/25/15
to silverst...@googlegroups.com
Chris, can you provide a bit more information on this? Especially on how to do this in v3.1. Or is there a setting somewhere where I can configure this? Maybe you already know off hand.

--
You received this message because you are subscribed to the Google Groups "SilverStripe Core Development" group.
To unsubscribe from this group and stop receiving emails from it, send an email to silverstripe-d...@googlegroups.com.
To post to this group, send email to silverst...@googlegroups.com.
Visit this group at http://groups.google.com/group/silverstripe-dev.
For more options, visit https://groups.google.com/d/optout.

Patrick Nelson

unread,
Jun 25, 2015, 3:51:43 PM6/25/15
to silverst...@googlegroups.com
Just an update -- I found this to be an easy fix for my situation, since the only Versioned objects that I wish to apply this too are pages, I did the following. I added a new class called "CustomSiteTree" (for example) and just setup my "Page" object to extend that. For any Googlers, here's the first implementation of my code that I used, in case anyone else finds this useful.


class CustomSiteTree extends SiteTree {

// This is a workaround to prevent this from being a page type option!
private static $hide_ancestor = "CustomSiteTree";

/**
* Updates the CMS and user interface to prevent users from seeing indications that they can delete something when
* actually they cannot since it's still published. This doesn't get in the way of unpublishing, only deleting from
* draft.
*
* IMPORTANT: This can only be done via override since setting it up in an extension will not work for users who are
* administrators, since unfortunately SilverStripe doesn't bother to even call extensions if it sees that you're an
* admin.
*
* @param null $member
* @return bool
*/
public function canDelete($member = null) {
if ($this->isPublished()) return false;
return parent::canDelete($member);
}


/**
* Extra fail-safe (just in case it is needed) to prevent accidental removal of pages which may already be published.
*/
public function delete() {
$stage = Versioned::current_stage();
if ($stage == "Stage") {
// See if this currently has a Live version.
if ($this->isPublished()) {
// Register an error visible to the user and return immediately preventing delete.
user_error("Cannot delete draft when still published.", E_USER_WARNING);
return;
}

}

parent::delete();
}

}

This seems to work reasonably well for me and prevents those pesky issues where the front-end is showing a ghost page which cannot be removed since it can only be administered via some other area than the site tree interface in the CMS (which goes through the effort of enumerating pages that don't exist in draft but still exist in *_Live tables, i.e. published mode). This is because typically the CMS only references the draft table when fetching objects for listing purposes (e.g. has_many relations for populating a GridField)

Florian Thoma

unread,
Jun 26, 2015, 6:05:13 PM6/26/15
to silverst...@googlegroups.com
I have once written a module to prevent that: https://github.com/xini/silverstripe-cmshidedeletedraft

Patrick Nelson

unread,
Jun 27, 2015, 4:11:00 PM6/27/15
to silverst...@googlegroups.com
Yeah Florian, that $actions->removeByName('action_delete') looks like a good approach too.  It only updates the UI in one spot though isn't that correct? Would that still prevent grid fields from accidentally deleting versioned objects (e.g. SiteTree instances) from draft but not from published? In my code I protected against that via overriding ->delete() and registering user errors so the developer can clean up his act (i.e. either disable the delete action directly via removing the component from the grid field or via "hard" delete). This hard-delete would be, like what I eventually setup later, managed via property on inheriting objects ($hard_delete = true) which would perform a ->doUnpublish() if it were true when attempting to do a draft delete. This helps ensure database consistency and issues, like in grid fields, where you can't find the object if it doesn't exist in draft table yet it's still live on the site (effectively orphaning it and making a "ghost" entry as my client called it :). Can you end parentheticals with a happy face?

--
Reply all
Reply to author
Forward
0 new messages