Source for file form.php

Documentation is available at form.php

  1. <?php
  2. /**
  3.  * @package    FrameworkOnFramework
  4.  * @subpackage form
  5.  * @copyright  Copyright (C) 2010 - 2012 Akeeba Ltd. All rights reserved.
  6.  * @license    GNU General Public License version 2 or later; see LICENSE.txt
  7.  */
  8. // Protect from unauthorized access
  9. defined('_JEXEC'or die;
  10.  
  11. /**
  12.  * FOFForm is an extension to JForm which support not only edit views but also
  13.  * browse (record list) and read (single record display) views based on XML
  14.  * forms.
  15.  *
  16.  * @package  FrameworkOnFramework
  17.  * @since    2.0
  18.  */
  19. class FOFForm extends JForm
  20. {
  21.     /**
  22.      * The model attached to this view
  23.      *
  24.      * @var FOFModel 
  25.      */
  26.     protected $model;
  27.  
  28.     /**
  29.      * The view used to render this form
  30.      *
  31.      * @var FOFView 
  32.      */
  33.     protected $view;
  34.  
  35.     /**
  36.      * Method to get an instance of a form.
  37.      *
  38.      * @param   string  $name     The name of the form.
  39.      * @param   string  $data     The name of an XML file or string to load as the form definition.
  40.      * @param   array   $options  An array of form options.
  41.      * @param   string  $replace  Flag to toggle whether form fields should be replaced if a field
  42.      *                             already exists with the same group/name.
  43.      * @param   string  $xpath    An optional xpath to search for the fields.
  44.      *
  45.      * @return  object  FOFForm instance.
  46.      *
  47.      * @since   2.0
  48.      * @throws  InvalidArgumentException if no data provided.
  49.      * @throws  RuntimeException if the form could not be loaded.
  50.      */
  51.     public static function getInstance($name$data null$options array()$replace true$xpath false)
  52.     {
  53.         // Reference to array with form instances
  54.         $forms &self::$forms;
  55.  
  56.         // Only instantiate the form if it does not already exist.
  57.         if (!isset($forms[$name]))
  58.         {
  59.             $data trim($data);
  60.  
  61.             if (empty($data))
  62.             {
  63.                 throw new InvalidArgumentException(sprintf('FOFForm::getInstance(name, *%s*)'gettype($data)));
  64.             }
  65.  
  66.             // Instantiate the form.
  67.             $forms[$namenew FOFForm($name$options);
  68.  
  69.             // Load the data.
  70.             if (substr(trim($data)01== '<')
  71.             {
  72.                 if ($forms[$name]->load($data$replace$xpath== false)
  73.                 {
  74.                     throw new RuntimeException('FOFForm::getInstance could not load form');
  75.                 }
  76.             }
  77.             else
  78.             {
  79.                 if ($forms[$name]->loadFile($data$replace$xpath== false)
  80.                 {
  81.                     throw new RuntimeException('FOFForm::getInstance could not load file');
  82.                 }
  83.             }
  84.         }
  85.  
  86.         return $forms[$name];
  87.     }
  88.  
  89.     /**
  90.      * Returns the value of an attribute of the form itself
  91.      *
  92.      * @param   string  $attribute  The name of the attribute
  93.      * @param   mixed   $default    Optional default value to return
  94.      *
  95.      * @return  mixed 
  96.      *
  97.      * @since 2.0
  98.      */
  99.     public function getAttribute($attribute$default null)
  100.     {
  101.         $value $this->xml->attributes()->$attribute;
  102.  
  103.         if (is_null($value))
  104.         {
  105.             return $default;
  106.         }
  107.         else
  108.         {
  109.             return (string) $value;
  110.         }
  111.     }
  112.  
  113.     /**
  114.      * Loads the CSS files defined in the form, based on its cssfiles attribute
  115.      *
  116.      * @return  void 
  117.      *
  118.      * @since 2.0
  119.      */
  120.     public function loadCSSFiles()
  121.     {
  122.         // Support for CSS files
  123.         $cssfiles $this->getAttribute('cssfiles');
  124.  
  125.         if (!empty($cssfiles))
  126.         {
  127.             $cssfiles explode(','$cssfiles);
  128.  
  129.             foreach ($cssfiles as $cssfile)
  130.             {
  131.                 FOFTemplateUtils::addCSS(trim($cssfile));
  132.             }
  133.         }
  134.  
  135.         // Support for LESS files
  136.         $lessfiles $this->getAttribute('lessfiles');
  137.  
  138.         if (!empty($lessfiles))
  139.         {
  140.             $lessfiles explode(','$lessfiles);
  141.  
  142.             foreach ($lessfiles as $def)
  143.             {
  144.                 $parts explode('||'$def2);
  145.                 $lessfile $parts[0];
  146.                 $alt (count($parts1trim($parts[1]null;
  147.                 FOFTemplateUtils::addLESS(trim($lessfile)$alt);
  148.             }
  149.         }
  150.     }
  151.  
  152.     /**
  153.      * Loads the Javascript files defined in the form, based on its jsfiles attribute
  154.      *
  155.      * @return  void 
  156.      *
  157.      * @since 2.0
  158.      */
  159.     public function loadJSFiles()
  160.     {
  161.         $jsfiles $this->getAttribute('jsfiles');
  162.  
  163.         if (empty($jsfiles))
  164.         {
  165.             return;
  166.         }
  167.  
  168.         $jsfiles explode(','$jsfiles);
  169.  
  170.         foreach ($jsfiles as $jsfile)
  171.         {
  172.             FOFTemplateUtils::addJS(trim($jsfile));
  173.         }
  174.     }
  175.  
  176.     /**
  177.      * Returns a reference to the protected $data object, allowing direct
  178.      * access to and manipulation of the form's data.
  179.      *
  180.      * @return   JRegistry  The form's data registry
  181.      *
  182.      * @since 2.0
  183.      */
  184.     public function getData()
  185.     {
  186.         return $this->data;
  187.     }
  188.  
  189.     /**
  190.      * Attaches a FOFModel to this form
  191.      *
  192.      * @param   FOFModel  &$model  The model to attach to the form
  193.      *
  194.      * @return  void 
  195.      */
  196.     public function setModel(FOFModel &$model)
  197.     {
  198.         $this->model = $model;
  199.     }
  200.  
  201.     /**
  202.      * Returns the FOFModel attached to this form
  203.      *
  204.      * @return FOFModel 
  205.      */
  206.     public function &getModel()
  207.     {
  208.         return $this->model;
  209.     }
  210.  
  211.     /**
  212.      * Attaches a FOFView to this form
  213.      *
  214.      * @param   FOFView  &$view  The view to attach to the form
  215.      *
  216.      * @return  void 
  217.      */
  218.     public function setView(FOFView &$view)
  219.     {
  220.         $this->view = $view;
  221.     }
  222.  
  223.     /**
  224.      * Returns the FOFView attached to this form
  225.      *
  226.      * @return FOFView 
  227.      */
  228.     public function &getView()
  229.     {
  230.         return $this->view;
  231.     }
  232.  
  233.     /**
  234.      * Method to get an array of FOFFormHeader objects in the headerset.
  235.      *
  236.      * @return  array  The array of FOFFormHeader objects in the headerset.
  237.      *
  238.      * @since   2.0
  239.      */
  240.     public function getHeaderset()
  241.     {
  242.         $fields array();
  243.  
  244.         $elements $this->findHeadersByGroup();
  245.  
  246.         // If no field elements were found return empty.
  247.  
  248.         if (empty($elements))
  249.         {
  250.             return $fields;
  251.         }
  252.  
  253.         // Build the result array from the found field elements.
  254.  
  255.         foreach ($elements as $element)
  256.         {
  257.             // Get the field groups for the element.
  258.             $attrs $element->xpath('ancestor::headers[@name]/@name');
  259.             $groups array_map('strval'$attrs $attrs array());
  260.             $group implode('.'$groups);
  261.  
  262.             // If the field is successfully loaded add it to the result array.
  263.             if ($field $this->loadHeader($element$group))
  264.             {
  265.                 $fields[$field->id$field;
  266.             }
  267.         }
  268.  
  269.         return $fields;
  270.     }
  271.  
  272.     /**
  273.      * Method to get an array of <header /> elements from the form XML document which are
  274.      * in a control group by name.
  275.      *
  276.      * @param   mixed    $group   The optional dot-separated form group path on which to find the fields.
  277.      *                             Null will return all fields. False will return fields not in a group.
  278.      * @param   boolean  $nested  True to also include fields in nested groups that are inside of the
  279.      *                             group for which to find fields.
  280.      *
  281.      * @return  mixed  Boolean false on error or array of SimpleXMLElement objects.
  282.      *
  283.      * @since   2.0
  284.      */
  285.     protected function &findHeadersByGroup($group null$nested false)
  286.     {
  287.         $false false;
  288.         $fields array();
  289.  
  290.         // Make sure there is a valid JForm XML document.
  291.         if (!($this->xml instanceof SimpleXMLElement))
  292.         {
  293.             return $false;
  294.         }
  295.  
  296.         // Get only fields in a specific group?
  297.         if ($group)
  298.         {
  299.             // Get the fields elements for a given group.
  300.             $elements &$this->findHeader($group);
  301.  
  302.             // Get all of the field elements for the fields elements.
  303.             foreach ($elements as $element)
  304.             {
  305.                 // If there are field elements add them to the return result.
  306.                 if ($tmp $element->xpath('descendant::header'))
  307.                 {
  308.                     // If we also want fields in nested groups then just merge the arrays.
  309.                     if ($nested)
  310.                     {
  311.                         $fields array_merge($fields$tmp);
  312.                     }
  313.  
  314.                     // If we want to exclude nested groups then we need to check each field.
  315.                     else
  316.                     {
  317.                         $groupNames explode('.'$group);
  318.  
  319.                         foreach ($tmp as $field)
  320.                         {
  321.                             // Get the names of the groups that the field is in.
  322.                             $attrs $field->xpath('ancestor::headers[@name]/@name');
  323.                             $names array_map('strval'$attrs $attrs array());
  324.  
  325.                             // If the field is in the specific group then add it to the return list.
  326.                             if ($names == (array) $groupNames)
  327.                             {
  328.                                 $fields array_merge($fieldsarray($field));
  329.                             }
  330.                         }
  331.                     }
  332.                 }
  333.             }
  334.         }
  335.         elseif ($group === false)
  336.         {
  337.             // Get only field elements not in a group.
  338.             $fields $this->xml->xpath('descendant::headers[not(@name)]/header | descendant::headers[not(@name)]/headerset/header ');
  339.         }
  340.         else
  341.         {
  342.             // Get an array of all the <header /> elements.
  343.             $fields $this->xml->xpath('//header');
  344.         }
  345.  
  346.         return $fields;
  347.     }
  348.  
  349.     /**
  350.      * Method to get a header field represented as a FOFFormHeader object.
  351.      *
  352.      * @param   string  $name   The name of the header field.
  353.      * @param   string  $group  The optional dot-separated form group path on which to find the field.
  354.      * @param   mixed   $value  The optional value to use as the default for the field.
  355.      *
  356.      * @return  mixed  The FOFFormHeader object for the field or boolean false on error.
  357.      *
  358.      * @since   2.0
  359.      */
  360.     public function getHeader($name$group null$value null)
  361.     {
  362.         // Make sure there is a valid FOFForm XML document.
  363.         if (!($this->xml instanceof SimpleXMLElement))
  364.         {
  365.             return false;
  366.         }
  367.  
  368.         // Attempt to find the field by name and group.
  369.         $element $this->findHeader($name$group);
  370.  
  371.         // If the field element was not found return false.
  372.         if (!$element)
  373.         {
  374.             return false;
  375.         }
  376.  
  377.         return $this->loadHeader($element$group$value);
  378.     }
  379.  
  380.     /**
  381.      * Method to get a header field represented as an XML element object.
  382.      *
  383.      * @param   string  $name   The name of the form field.
  384.      * @param   string  $group  The optional dot-separated form group path on which to find the field.
  385.      *
  386.      * @return  mixed  The XML element object for the field or boolean false on error.
  387.      *
  388.      * @since   2.0
  389.      */
  390.     protected function findHeader($name$group null)
  391.     {
  392.         $element false;
  393.         $fields array();
  394.  
  395.         // Make sure there is a valid JForm XML document.
  396.         if (!($this->xml instanceof SimpleXMLElement))
  397.         {
  398.             return false;
  399.         }
  400.  
  401.         // Let's get the appropriate field element based on the method arguments.
  402.         if ($group)
  403.         {
  404.             // Get the fields elements for a given group.
  405.             $elements &$this->findGroup($group);
  406.  
  407.             // Get all of the field elements with the correct name for the fields elements.
  408.             foreach ($elements as $element)
  409.             {
  410.                 // If there are matching field elements add them to the fields array.
  411.                 if ($tmp $element->xpath('descendant::header[@name="' $name '"]'))
  412.                 {
  413.                     $fields array_merge($fields$tmp);
  414.                 }
  415.             }
  416.  
  417.             // Make sure something was found.
  418.             if (!$fields)
  419.             {
  420.                 return false;
  421.             }
  422.  
  423.             // Use the first correct match in the given group.
  424.             $groupNames explode('.'$group);
  425.  
  426.             foreach ($fields as &$field)
  427.             {
  428.                 // Get the group names as strings for ancestor fields elements.
  429.                 $attrs $field->xpath('ancestor::headerfields[@name]/@name');
  430.                 $names array_map('strval'$attrs $attrs array());
  431.  
  432.                 // If the field is in the exact group use it and break out of the loop.
  433.                 if ($names == (array) $groupNames)
  434.                 {
  435.                     $element &$field;
  436.                     break;
  437.                 }
  438.             }
  439.         }
  440.         else
  441.         {
  442.             // Get an array of fields with the correct name.
  443.             $fields $this->xml->xpath('//header[@name="' $name '"]');
  444.  
  445.             // Make sure something was found.
  446.             if (!$fields)
  447.             {
  448.                 return false;
  449.             }
  450.  
  451.             // Search through the fields for the right one.
  452.             foreach ($fields as &$field)
  453.             {
  454.                 // If we find an ancestor fields element with a group name then it isn't what we want.
  455.                 if ($field->xpath('ancestor::headerfields[@name]'))
  456.                 {
  457.                     continue;
  458.                 }
  459.  
  460.                 // Found it!
  461.                 else
  462.                 {
  463.                     $element &$field;
  464.                     break;
  465.                 }
  466.             }
  467.         }
  468.  
  469.         return $element;
  470.     }
  471.  
  472.     /**
  473.      * Method to load, setup and return a FOFFormHeader object based on field data.
  474.      *
  475.      * @param   string  $element  The XML element object representation of the form field.
  476.      * @param   string  $group    The optional dot-separated form group path on which to find the field.
  477.      * @param   mixed   $value    The optional value to use as the default for the field.
  478.      *
  479.      * @return  mixed  The FOFFormHeader object for the field or boolean false on error.
  480.      *
  481.      * @since   2.0
  482.      */
  483.     protected function loadHeader($element$group null$value null)
  484.     {
  485.         // Make sure there is a valid SimpleXMLElement.
  486.         if (!($element instanceof SimpleXMLElement))
  487.         {
  488.             return false;
  489.         }
  490.  
  491.         // Get the field type.
  492.         $type $element['type'? (string) $element['type''field';
  493.  
  494.         // Load the JFormField object for the field.
  495.         $field $this->loadHeaderType($type);
  496.  
  497.         // If the object could not be loaded, get a text field object.
  498.         if ($field === false)
  499.         {
  500.             $field $this->loadHeaderType('field');
  501.         }
  502.  
  503.         // Setup the FOFFormHeader object.
  504.         $field->setForm($this);
  505.  
  506.         if ($field->setup($element$value$group))
  507.         {
  508.             return $field;
  509.         }
  510.         else
  511.         {
  512.             return false;
  513.         }
  514.     }
  515.  
  516.     /**
  517.      * Proxy for {@link FOFFormHelper::loadFieldType()}.
  518.      *
  519.      * @param   string   $type  The field type.
  520.      * @param   boolean  $new   Flag to toggle whether we should get a new instance of the object.
  521.      *
  522.      * @return  mixed  FOFFormField object on success, false otherwise.
  523.      *
  524.      * @since   2.0
  525.      */
  526.     protected function loadFieldType($type$new true)
  527.     {
  528.         return FOFFormHelper::loadFieldType($type$new);
  529.     }
  530.  
  531.     /**
  532.      * Proxy for {@link FOFFormHelper::loadHeaderType()}.
  533.      *
  534.      * @param   string   $type  The field type.
  535.      * @param   boolean  $new   Flag to toggle whether we should get a new instance of the object.
  536.      *
  537.      * @return  mixed  FOFFormHeader object on success, false otherwise.
  538.      *
  539.      * @since   2.0
  540.      */
  541.     protected function loadHeaderType($type$new true)
  542.     {
  543.         return FOFFormHelper::loadHeaderType($type$new);
  544.     }
  545.  
  546.     /**
  547.      * Proxy for {@link FOFFormHelper::loadRuleType()}.
  548.      *
  549.      * @param   string   $type  The rule type.
  550.      * @param   boolean  $new   Flag to toggle whether we should get a new instance of the object.
  551.      *
  552.      * @return  mixed  JFormRule object on success, false otherwise.
  553.      *
  554.      * @see     FOFFormHelper::loadRuleType()
  555.      * @since   2.0
  556.      */
  557.     protected function loadRuleType($type$new true)
  558.     {
  559.         return FOFFormHelper::loadRuleType($type$new);
  560.     }
  561.  
  562.     /**
  563.      * Proxy for {@link FOFFormHelper::addFieldPath()}.
  564.      *
  565.      * @param   mixed  $new  A path or array of paths to add.
  566.      *
  567.      * @return  array  The list of paths that have been added.
  568.      *
  569.      * @since   2.0
  570.      */
  571.     public static function addFieldPath($new null)
  572.     {
  573.         return FOFFormHelper::addFieldPath($new);
  574.     }
  575.  
  576.     /**
  577.      * Proxy for {@link FOFFormHelper::addHeaderPath()}.
  578.      *
  579.      * @param   mixed  $new  A path or array of paths to add.
  580.      *
  581.      * @return  array  The list of paths that have been added.
  582.      *
  583.      * @since   2.0
  584.      */
  585.     public static function addHeaderPath($new null)
  586.     {
  587.         return FOFFormHelper::addHeaderPath($new);
  588.     }
  589.  
  590.     /**
  591.      * Proxy for FOFFormHelper::addFormPath().
  592.      *
  593.      * @param   mixed  $new  A path or array of paths to add.
  594.      *
  595.      * @return  array  The list of paths that have been added.
  596.      *
  597.      * @see     FOFFormHelper::addFormPath()
  598.      * @since   2.0
  599.      */
  600.     public static function addFormPath($new null)
  601.     {
  602.         return FOFFormHelper::addFormPath($new);
  603.     }
  604.  
  605.     /**
  606.      * Proxy for FOFFormHelper::addRulePath().
  607.      *
  608.      * @param   mixed  $new  A path or array of paths to add.
  609.      *
  610.      * @return  array  The list of paths that have been added.
  611.      *
  612.      * @see FOFFormHelper::addRulePath()
  613.      * @since   2.0
  614.      */
  615.     public static function addRulePath($new null)
  616.     {
  617.         return FOFFormHelper::addRulePath($new);
  618.     }
  619. }

Documentation generated on Tue, 19 Nov 2013 15:03:36 +0100 by phpDocumentor 1.4.3