1. The 3.8 code for Fabrik is now available on github, in the 'master' branch. If you are familiar with updating Fabrik from github, we would appreciate it if you could test this code on J! 3.8 for us. Once we have some feedback, we'll build a 3.8 release.

PHP form plugin

Mar 7, 2017
PHP form plugin

  • Introduction(top)

    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(top)


    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. In Fabrik version 2 these files are located in /components/com_fabrik/plugins/forms/fabrik/php/scripts.
      • In Fabrik 3 these files are located in /plugins/fabrik_form/php/scripts/ .
      • In Fabrik 2, It is location in components/com_fabrik/plugins/form/fabrikphp
    • The Joomla framework is available to these scripts, so for example you can access the Joomla database with :
      PHP:
      $db = JFactory::getDBO();
    • 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 (top)


    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
    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 (top)

    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(top)


    Accessing Form Data (top)

    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 = JFactory::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'
    Fabrik 3.0:
    $formModel->_formData // onBeforeStore: use full element names 'table___element'
          //for onAfterProcess - use short element names: 'element' - no table name
    Fabrik 3.1:
    $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)
    Fabrik 3.2 onBeforeCalculation, onAfterProcess (Jan 2015)
    $data['table___element']

    // All versions of Fabrik also have a $formModel->fullFormData, which will contain the data keyed by full name, even onAfterProcess.
     
    The way Fabrik handles repeat data changed between 3.0 and 3.2/1. In 3.0, repeat group data was stored in a 'join' array in formData, keyed by the groups ID. So $formModel->_formData['join'][123]['repeat_table___foo'] would be an array containing each repeated value. In 3.1/2, this got simplified, with the ['join'] array being remoed, so $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:

    Fabrik 3.0:
    echo "<pre>";print_r($formModel->_formData);exit;
    Fabrik 3.1:
    echo "<pre>";print_r($formModel->data);exit;
    or
    echo "<pre>";print_r($formModel->formData);exit;
    or
    echo "<pre>";print_r($data);exit;
     
    In Fabrik 3.0 or less:
    Joined elements (e.g. muliselect database joins, file uploads with multiple files being uploaded) and elements in joined groups. have their data nested in the array, so fore example to access the element 'countries___regions' in join id 6 you would do :
    PHP:

    $regions = $formModel->_data['join'][6]['countries___regions'] // for getTopContent, getBottomContent, getEndContent - full element names
    $regions = $formModel->formData['join'][6]['countries___regions'] // for onAfterProcess - full element names
     
    In Fabrik 3.1 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(top)

    only tested with Fabrik3.4.3 and onBeforeStore (check with var_dump($formModel->getOrigData()[0]);exit; )
    Code (Text):
    $origData = $formModel->getOrigData()[0];

    Updating a form's value on Save(top)

    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);

    // in Fabrik 3.0 or less, to update data in a join (with id = 1) use this syntax:
    $formModel->updateFormData("join.1.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.

    Conditionally updating a form's value on Save(top)

    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(top)

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

    Fabrik 3.1. onward, use
    Code (Text):
    $formModel->data['table___element']='abc'
    for manipulating the data onLoad.

    Stopping form submission (top)

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

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

    /**
    * this is a very simple example of a script to stop the form being processed
    * The form is then redisplayed with an error
    * notice at the top of the form (and the previously filled in data still visible)
    */


    // The error message 'woops' will be assinged to the element 'tablename_elementname'
    $formModel->_arErrors['tablename___elementname'][] = 'woops!';
    return false;
     
    For Fabrik 3.1
    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 _arErrors['tablemame___elementname'] values is set...

    Totalling radio buttons and placing the result in an element (top)

    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(top)

    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 = JFactory::getDbo();
      $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(top)

    PHP:

    $db = JFactory::getDbo();
    $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(top)


    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 = JFactory::getDbo();
    $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();
    }

     

    Get row ID of a form(top)

    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.
  • Loading...
ontarget, nelly, joomlamate and 3 others like this.