HomeDevCentral

Undo mechanism

Description

Undo mechanism

Summary:
We want to allow users to immediately cancel destructive operations.
An undo link or button is probably more convenient for most users
than an "are you sure?" confirmation.

For destructive operations, we first considered soft deletes. Yet,
http://rdingwall.com/2009/11/20/the-trouble-with-soft-delete/ make
a strong case against soft deletes.

We so provide a way to store undoable operations in a stack:

  • the UndoStore is a class to store an undoable object
  • the Undoable interface defines an object with undo capability
  • the WithUndo trait implements Undoable, with default UndoStore options. It works well for Eloquent models when you want to restore with ->save() after a ->delete().
  • the UndoStack is a LIFO collection of UndoStore instances

The workflow is so:

  1. Put the destructive operation's subject into an UndoStore instance
  2. Push the UndoStore instance to the stack
  3. Be sure we've a reference to this stack somewhere, e.g. in session

This stack is stored in the session, accessible through any Controller
through the UndoesOperations trait.

The SplDoublyLinkedList has been chosen as it's lightweight in memory,
well serializable, iterable as LIFO.

Compatibility with plain PHP / Symfony SessionInterface / Laravel has
been a special consideration to design this solution.

Test Plan:

  • Unit tests
  • Implemented to undo external sources unlink in D445

Reviewers: dereckson

Differential Revision: https://devcentral.nasqueron.org/D522

Details

Provenance
derecksonAuthored on Jul 20 2016, 01:18
Differential Revision
D522: Undo mechanism
Parents
rGROVEe474ff1134ce: New helper function: authurl
Branches
Unknown
Tags
Unknown
Tasks
T905: UndoStack

Event Timeline

Could be split in two parts:

  • keruald/undo (rKUNDO for example) for generic implementation
  • rGROVE or a specific laravel service provider change for Laravel specific stuff
/app/Undo/UndoStore.php
39

Objets we can restore should implement a specific interface we provide, so we don't use arbitrary calls, but a known method defined by a correct abstraction.

46

Like restoreMethod isn't really cool, do we have a use case to provide here context not available in the serialized object itself?