Preview system
- Home
- Creating forms
- Preview system
SproutCMS's built-in preview system, useful for admin forms which will store data to be displayed on the front end, has been described as being simultaneously a brilliant and a horrible idea.
The way it works is this:
- Data is submitted via a POST form (usually the add or edit form for a
ManagedAdminController
of some sort, e.g.PageAdminController
) - Temporary database tables are created and populated with content needed to render the preview, by a nifty hack which changes the database table name prefix from
sprout_
to something random. - The POSTed data are saved into the temporary tables using the controller's
_editSave
method - The normal front-end display method is called to render the preview (e.g.
PageController::view
)
The good thing about this method is that there's no need to write specific code to handle previews for each bit of data which can be previewed - which would usually be done by mangling the $_POST data into formats expected by the preview. The bad thing is that if the view includes data from a wide variety of sources, much data will need to be temporarily duplicated in step 2, making it a computationally intensive procedure. Generally this isn't a problem, but it could be if there are many admins making frequent edits which need previewing. It wouldn't be suitable for implementing a popular wiki, for instance.
Making it work
Add a preview button
The first thing you need to do is add a preview button to the add/edit form. If you're using a ManagedAdminController
, all you need to do is update that controller's _getEditSubActions method to include an action called _preview with a URL to a preview method (to be written next), as per the following example:
modules/Example/Controllers/Admin/ExampleAdminController.php
public function _getEditSubActions($item_id) { $actions = parent::_getEditSubActions($item_id); $actions['_preview'] = "admin/call/{$this->controller_name}/preview/{$item_id}"; return $actions; }
Handle the preview submission
This preview method handles the above submission. The Preview
helper sets up of the temporary tables which provide the preview functionality. Here's an example:
modules/Example/Controllers/Admin/ExampleAdminController.php
public function preview($item_id) { $tables = [ 'example_table1' => 0, 'example_table2' => 1, 'example_table3' => ['active' => 1], ]; Preview::load($this, $tables, $item_id); $front_end = new ExampleController(); Preview::run($front_end, 'view', [$item_id]); }
The Preview::load
call must specify ALL the tables into which data will be saved. Any tables not specified will have data overwritten. The amount of data duplicated depends on the conditions supplied for each table as described in the API docs.
Once the POST data for the preview has been saved, the preview can be run via Preview::run
with the appropriate front-end view method. Typically the names of the admin and front-end controllers align, e.g. ExampleAdminController
and ExampleController
.
Special considerations
If the _editSave
method of the relevant ManagedAdminController
performs additional actions, such as sending emails, setting session messages or redirecting to another URL, these will have to be disabled somehow when the preview
method calls _editSave
. One way is to simply set a class attribute in_preview
to false, and checking that attribute in the _editSave
method:
modules/Example/Controllers/Admin/ExampleAdminController.php
public function preview($item_id) { $this->is_preview = true; // ... as per the earlier example } public function _editSave($item_id) { // validation etc. goes here if (empty($this->is_preview)) { Notification::confirm('Record saved'); $this->sendEmails($item_id); Url::redirect('some/url'); } }