PHP form plugin

  • Views Views: 116,335
  • Last updated Last updated:

Navigation

         Form Article Plugin Tutorial
      Autofill form plugin
      Clone form plugin
      Comment form plugin
      Email form plugin
      EXIF form plugin
      FTP form plugin
      J2store form plugin
      Kunena form plugin
      Limit form plugin
      Logs form plugin
      Mailchimp form plugin
      Paginate form plugin
      Paypal form plugin
      PHP form plugin
      Pingdotfm form plugin
      Receipt form plugin
      Redirect form plugin
      REST form plugin
      Slack form plugin (+)
      SMS form plugin
      Twitter form plugin
      Upsert form plugin
      VBforum form plugin
      Create a Search Form
      Accordion Form Groups
  • Introduction​

    Sometimes you are going to need to run some specific code that is not provided for by one of the other form submission plug-ins. At this point the highly flexible Run PHP plug-in is a godsend.

    Options​


    php.png


    • Process scripts - State where in the form submission process you would like the script to be executed.
    • PHP File- Select the PHP file you would like to run.These files are located in /plugins/fabrik_form/php/scripts/ .
    • The Joomla framework is available to these scripts, so for example you can access the Joomla database with :
      PHP:
      $db =Joomla\CMS\Factory::getContainer()->get('DatabaseDriver');
    • PHP code to execute on from submission - If no script is selected then the code entered here will be run instead.
    Any script you want to use should be located in the 'scripts' sub folder of this directory.
    For best security practices you should always add this to the top of your custom php scripts:
    PHP:

    // Check to ensure this file is included in Joomla!
    defined('_JEXEC') or die();
    this stops the script from being executed outside of Joomla/Fabrik.

    Plugin Locations​


    The plug-in allows you to run your PHP at various locations/times within a fabrik form:

    Locations :
    • getTopContent - will insert anything that has been return'ed from your PHP script into the top of the form
    • getBottomContent - will insert anything that has been return'ed from your PHP script into the bottom of the form
    In these cases it is the string value returned by the script which is inserted into the page. Use a return statement in your script (eg return 'Hello world'; rather than echo statements.

    Times :

    The main "times" (or "hooks") that the PHP plugin can be set to run on are:
    • onLoad - runs when the form has been loaded, after its data has been created and assigned
    • onError - When the form is submitted it is first validated, if a Validation error occurs then this hook is triggered allowing you to for example, alter the $model->_arErrors error array or log which Validation errors were set.
    • onBeforeProcess - occurs at the start of a form submission, before the posted data has been assigned to the form model, but after the form has been validated
    • onBeforeStore - occurs after onBeforeProcess and occurs after any fileuploads have been dealt with
    • onAfterProcess - occurs after onBeforeStore once the form has submitted its data to the database table
    • onDeleteRowsForm - the code is run on form delete and on list delete (see example below)
    There are other hooks, which are documented in the tooltip for this setting.

    Validation :If any of the scripts running during the form submission return false, then the form submission is halted.

    Refresh display​

    If using onBeforeLoad(), and your script modifies the database used by your form, or your form fields, you should wish that your display reflects your modifications. In that case, Fabrik should be forced to re-read data from the database when call getData(), just after the onBeforeLoad() hook runs.
    For this use :
    PHP:
    unset($formModel->_data);

    Examples​


    Accessing Form Data​

    Usually, the best way to get an element's data is with the $formModel->getElementData() method, which takes the full element name, and three optional arguments:

    PHP:

    * @param string $fullName full element name
    * @param bool $raw get raw data
    * @param mixed $default value
    * @param string $repeatCount repeat count if needed
    The getElementData() method should work on any hook for the PHP form plugin, with the exception of onBeforeLoad (as there is no element data to get at that point). It should also work anywhere $formModel is availabe, not just in the PHP form plugin, as long as it is running at a point where form data has actually been loaded.
    Examples:
    PHP:

    // To get the content of a simple Field element
    $foo = $formModel->getElementData('mytable___foo');
    // To get the content of the second occurence of an element in a repeat group (group repeats are numbered from 0)
    $foo = $formModel->getElementData('my_repeat_table___foo', false, '', 1);

    /*
    *To get the raw value for a Database join element, which is set to display as a dropdown.
    * Note that the data in a join element, or any element which has multiple value (checkbox, radiom etc)
    * will (almost always) be an array, as it can contain multiple values. For a single value dropdown, we
    * will typically just want the first (and only) value in that array, so the second line here simply extracts
    * the single result from the array.
    * Also note the use of the second argument, $raw, which fetches the 'value' rather than the 'label'
    */
    $foo = $formModel->getElementData('mytable___somejoin', true);
    $foo = is_array($foo) ? $foo[0] : $foo;

    /*
    * During a submission hook (like onBeforeProcess, onAfterProcess, etc), get the number of times a
    * group has been repeated, and fetch each value of foo. You'll need to know the group ID of your group
    * which is in the rightmost column of the main list of Groups on the backend. Here we'll use 123. On
    * submit, the totals for each group's repeats are in a hidden form variable called fabrik_repeat_group,
    * which we can fetch with the J! request API ($input->get()):
    $app = Joomla\CMS\Factory::getApplication();
    $input = $app->input; $group_id = 123;
    $repeatTotals = $input->get('fabrik_repeat_group', array(0), 'array');
    for ($repeats = 0; $repeats < $repeatTotals[$group_id]; $repeats++)
    {
    $foo = $formModel->getElementData('my_repeat_table___foo', false, $repeat);
    // some code to do something with $foo goes here
    }

    /*
    * An alternative approach to fetching all the repeated value for an element in a repeat group.
    * This time, we'll just get the element's value, without specifying a repeatCount, in which case
    * getElementData() will just hand us back an array which has all the repeated values.
    * Typically when doing something like this, you will be wanting to fetch the coresponding value
    * for another element in the same repeated instance of the group. So in this example, we'll use the key
    * from a foreach() to grab another element's value. This example assumes we're going to do math on
    * a 'cost' and 'qty', so specify $raw to make sure we get unformatted values.
    */
    $costs = $formModel->getElementData('my_repeat_table___cost', true);
    foreach ($costs as $key => $cost)
    {
    $qty = $formModel->getElementData('my_repeat_table___qty', true, 0, $key);
    // do something with $cost and $qty
    }

    Sometimes using getElementData() won't quite do what you need, or you simply want to access the data structure(s) yourself. The element data is easy to get at, the trick is simply knowing where it will be, depending on what phase of loading / processing you are running your code in.

    The form's data is stored as an array and can be accessed with
    PHP:

    $formModel->_data; // for getTopContent, getBottomContent, getEndContent - use full element names: 'table___element'

    $formModel->data //onload: use full element names 'table___element' e.g. $formModel->data['table___element']='abc';
    $formModel->formData // onBeforeStore: use full element names 'table___element'
    //for onAfterProcess - use short element names: 'element' - no table name (has issues with joined tables with identical column names (Jan. 2015)
    onBeforeCalculation, onAfterProcess
    $data['table___element']

    // All versions of Fabrik also have a $formModel->fullFormData, which will contain the data keyed by full name, even onAfterProcess.

    $formModel->formData['repeat_table___foo'] is the array of repeated values.


    To quickly see the structure of your form's data set this as your code:
    PHP:

    echo "<pre>";print_r($formModel->data);exit;
    or
    echo "<pre>";print_r($formModel->formData);exit;
    or
    echo "<pre>";print_r($data);exit;

    Joined data is accessed in the same way as the main list's fields, e.g.
    PHP:

    $regions = $formModel->formData['countries___regions'];

    N.B : In the php code field your PHP code can make use of {Placeholders} (not possible in php-script-files).

    Accessing form's original data​

    only tested with Fabrik3.4.3 and onBeforeStore (check with var_dump($formModel->getOrigData()[0]);exit; )
    24-02-24: Tested on F4, J4 and OnAfterProcess event and this code (below) worked


    Code:

    $origData = $formModel->getOrigData()[0];
    $originalFieldValue = $origData->mytable___myfield;

    For an example of this in use see:
    https://fabrikar.com/forums/index.php?threads/approve-form-before-pdf-generation.47518/#post-246324

    Updating a form's value on Save​

    Often you will want to update the data that has been submitted by the form, run your plugin onBeforeProcess. To do this the php would be:
    PHP:

    $formModel->updateFormData('tablename___elementname', 'string value', true);


    If you need to update your data AFTER the form has been processed (and data has been written to the database), using onAfterProcess, note that the tablename___ prefix will have been removed from $formModel->formData[], so use $formModel->formDataWithTableName[] instead to access data. Also, using updateFormData() will have no effect, you have to manually run a query to update your table.

    [HEADING=3]Conditionally updating a form's value on Save[/HEADING]
    Lets say we want to update the field 'sport's value to 'badminton' when the field name's value is 'rob'. To do this the php would be:
    [php]
    $name = $formModel->formData['tablename___name'];

    if ($name === 'rob')
    {
    $formModel->updateFormData('tablename___sport', 'badminton', true);
    }

    You must use full element names ('table___element') with the onBeforeStore setting and short element names ( 'element' - no table name) with the onAfterProcess setting.

    Updating a form's value before showing the form​

    This would use the same code as the above example except you set the "plugin location" to onLoad

    Code:
    $formModel->data['table___element']='abc';
    $formModel->data['table___element_raw']='abc';
    for manipulating the data onLoad.

    Stopping form submission​

    Set your plug-in to run 'onBeforeProcess' add this script:
    PHP:

    // stop form being processed and close form without a message when saved
    // will also close ajax modal form window
    return false;

    PHP:

    // The error message 'woops' will be assinged to the element 'tablename_elementname'
    $formModel->errors['tablename___elementname'][] = 'woops!';
    return false;

    in order to change the main error message, which will show automatically when any of the field error messages are set, you can set:
    PHP:

    $formModel->getForm()->error = "Sorry, that's not going to work.";

    this is only displayed if one of the ->errors['tablemame___elementname'] values is set...

    Totalling radio buttons and placing the result in an element​

    Say you want to total the selected values of three radio buttons and store their total in another element when the form is submitted:

    Lets say you have 3 radio Elements, called listname___radio1, listname___radio2 and listname___radio3, with values 1,2,3 and labels one,two,three.

    You want to total these and update a element 'listname___total'. You're php code would look like:
    PHP:

    $radio1 = (int)"{listname___radio1_raw}";
    $radio2 = (int)"{listname___radio2_raw}";
    $radio3 = (int)"{listname___radio3_raw}";
    $total = $radio1 + $radio2 + $radio3;

    $formModel->updateFormData("listname___total", $total, true);

    You would set it to run on both new and edit records, and to run on 'Start of form submission'

    IP Check​

    Say you have a form where you only want to record one record per IP address. Your form saves to the database table 'contacts' and stores the user's IP address in an element called 'ip':

    To stop the form from loading add an onLoad PHP form plugin with the following code:
    PHP:

    if (!$formModel->isNewRecord()) {
    $db = Joomla\CMS\Factory::getContainer()->get('DatabaseDriver');
    $query = $db->getQuery(true);
    $thisIp = $formModel->formData['contacts___ip'];
    $query->select('COUNT(*)')->from('contacts')->where('ip = ' . $db->quote($thisIp));
    $db->setQuery($query);
    $total = $db->loadResult();
    if ($total > 0)
    {
    return false;
    }
    }
    return true;

    Insert a record in another table and update a form's field with the records primary key​

    PHP:

    $db = Joomla\CMS\Factory::getContainer()->get('DatabaseDriver');
    $query = $db->getQuery(true);
    $query->insert('tablename')->set('field = ' . $db->quote('bar'))
    ->set('field2 = ' . $db->quote('{tablename___elementname}'));
    $db->setQuery($query);
    $db->execute();
    $id = $db->insertid();

    // Update form data with insert id
    $formModel->updateFormData('tablename___elementname2', $id);

    Decrease a value in another table​


    I have a list called Courses which holds the available courses that a user can sign up for.
    Courses have an element called spaces that is a number - example 20 spaces.
    When a user signs up for a course I would like the value of spaces to be -1 space.
    PHP:

    // signup___course_id is the form field which contains the course Id you are signing up for
    // We cast it to an array as it could be a select list or multiple select list.

    $courseIds = (array) $formModel->formData['signup___course_id'];

    // Get the db and the query
    $db = Joomla\CMS\Factory::getContainer()->get('DatabaseDriver');
    $query = $db->getQuery(true);

    foreach ($courseIds as $courseId)
    {
    // Clear down any previous query
    $query->clear();

    // Update the query to decrease the value contained in the field "spaces" by 1 for the current course id.
    $query->update('courses')->set('spaces = spaces - 1')->where('id = ' . (int) $courseId);
    $db->setQuery($query);
    $db->execute();
    }

    Do something on record deletion​

    The onDeleteRowsForm hook is called from the main list model deleteRows() method, which is called both when you do a list delete (potentially with multiple rows) and also from form controller when you delete from a form view.

    In both case, the form PHP plugin's onDeleteRowsForm() method is triggered, with the row data in $data, which is an array of arrays (Groups) of objects (rows). So you should always code it assuming that you may get called with multiple rows (deleting from a list will do that). Even if it's being called in the form context, it'll still be a two dimensional array of objects, it'll just be a single group with a single row in it.

    So ...
    Code:
    Code (Text):

    foreach ($data[0] as $group) {
    foreach ($group as $row) {
    // your rowid will be in $row->__pk_val
    // Elements will be in $row->tablename___fieldname
    }
    }

    Don't use {rowid}, as that's just a placeholder for the current row in form view. So it'll work if your code is running from a delete in a form context, but won't work if it's being called from a list delete. And as explained, you have to assume your code will get called from a list delete - the same plugin is being triggered. So use $row->__pk_val.

    For element data, use full element names, like $row->tablename___fieldname, or with the _raw suffix, $row->tablename___fieldname_raw (if your element is one with the concept of "value" and "label", like join Elements).
    https://fabrikar.com/forums/index.p...leterowsform-trigger-works.48475/#post-252810

    Get row ID of a form​

    When a form is loaded, it's rowid is located in the querystring. To retreive it, for example for database manipulations, use : '{rowid}' in the PHP code.

    Check if submission was via Copy button​

    Code:
    if ($formModel->copyingRow)

    Get Label for Dropdown Elements​

    PHP:

    $element_value = $formModel->data['yourtable___elementname_raw'];
    $elementModel = $formModel->getElement('yourtable___elementname');
    $element_label = $elementModel->getEmailValue($element_value, $formModel->formDataWithTableName, 0);

    Loading/showing a message when form is saved​

    This will display a message after the form is saved, usually at the top of the browser page. If you want to have the normal Fabrik success message displayed and you want an additional message box displayed with additional information, then the second param should be 'info' or 'notice'. If you want the Fabrik form's "Success Message" to be overridden, the second param should be "message".
    PHP:

    //!J4
    $app = Joomla\CMS\Factory::getApplication();
    $app->enqueueMessage('some message you want to send','notice');

    See the Joomla Documentation for more information about queuing messages.
Back
Top