1 <?php
  2 /**
  3  * @package    FrameworkOnFramework
  4  * @subpackage form
  5  * @copyright   Copyright (C) 2010-2016 Nicholas K. Dionysopoulos / 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('FOF_INCLUDED') or die;
 10 
 11 JLoader::import('joomla.form.helper');
 12 
 13 /**
 14  * FOFForm's helper class.
 15  * Provides a storage for filesystem's paths where FOFForm's entities reside and
 16  * methods for creating those entities. Also stores objects with entities'
 17  * prototypes for further reusing.
 18  *
 19  * @package  FrameworkOnFramework
 20  * @since    2.0
 21  */
 22 class FOFFormHelper extends JFormHelper
 23 {
 24     /**
 25      * Method to load a form field object given a type.
 26      *
 27      * @param   string   $type  The field type.
 28      * @param   boolean  $new   Flag to toggle whether we should get a new instance of the object.
 29      *
 30      * @return  mixed  JFormField object on success, false otherwise.
 31      *
 32      * @since   11.1
 33      */
 34     public static function loadFieldType($type, $new = true)
 35     {
 36         return self::loadType('field', $type, $new);
 37     }
 38 
 39     /**
 40      * Method to load a form field object given a type.
 41      *
 42      * @param   string   $type  The field type.
 43      * @param   boolean  $new   Flag to toggle whether we should get a new instance of the object.
 44      *
 45      * @return  mixed  JFormField object on success, false otherwise.
 46      *
 47      * @since   11.1
 48      */
 49     public static function loadHeaderType($type, $new = true)
 50     {
 51         return self::loadType('header', $type, $new);
 52     }
 53 
 54     /**
 55      * Method to load a form entity object given a type.
 56      * Each type is loaded only once and then used as a prototype for other objects of same type.
 57      * Please, use this method only with those entities which support types (forms don't support them).
 58      *
 59      * @param   string   $entity  The entity.
 60      * @param   string   $type    The entity type.
 61      * @param   boolean  $new     Flag to toggle whether we should get a new instance of the object.
 62      *
 63      * @return  mixed  Entity object on success, false otherwise.
 64      *
 65      * @since   11.1
 66      */
 67     protected static function loadType($entity, $type, $new = true)
 68     {
 69         // Reference to an array with current entity's type instances
 70         $types = &self::$entities[$entity];
 71 
 72         $key = md5($type);
 73 
 74         // Return an entity object if it already exists and we don't need a new one.
 75         if (isset($types[$key]) && $new === false)
 76         {
 77             return $types[$key];
 78         }
 79 
 80         $class = self::loadClass($entity, $type);
 81 
 82         if ($class !== false)
 83         {
 84             // Instantiate a new type object.
 85             $types[$key] = new $class;
 86 
 87             return $types[$key];
 88         }
 89         else
 90         {
 91             return false;
 92         }
 93     }
 94 
 95     /**
 96      * Attempt to import the JFormField class file if it isn't already imported.
 97      * You can use this method outside of JForm for loading a field for inheritance or composition.
 98      *
 99      * @param   string  $type  Type of a field whose class should be loaded.
100      *
101      * @return  mixed  Class name on success or false otherwise.
102      *
103      * @since   11.1
104      */
105     public static function loadFieldClass($type)
106     {
107         return self::loadClass('field', $type);
108     }
109 
110     /**
111      * Attempt to import the FOFFormHeader class file if it isn't already imported.
112      * You can use this method outside of JForm for loading a field for inheritance or composition.
113      *
114      * @param   string  $type  Type of a field whose class should be loaded.
115      *
116      * @return  mixed  Class name on success or false otherwise.
117      *
118      * @since   11.1
119      */
120     public static function loadHeaderClass($type)
121     {
122         return self::loadClass('header', $type);
123     }
124 
125     /**
126      * Load a class for one of the form's entities of a particular type.
127      * Currently, it makes sense to use this method for the "field" and "rule" entities
128      * (but you can support more entities in your subclass).
129      *
130      * @param   string  $entity  One of the form entities (field or rule).
131      * @param   string  $type    Type of an entity.
132      *
133      * @return  mixed  Class name on success or false otherwise.
134      *
135      * @since   2.0
136      */
137     public static function loadClass($entity, $type)
138     {
139         if (strpos($type, '.'))
140         {
141             list($prefix, $type) = explode('.', $type);
142             $altPrefix = $prefix;
143         }
144         else
145         {
146             $prefix = 'FOF';
147             $altPrefix = 'J';
148         }
149 
150         $class = JString::ucfirst($prefix, '_') . 'Form' . JString::ucfirst($entity, '_') . JString::ucfirst($type, '_');
151         $altClass = JString::ucfirst($altPrefix, '_') . 'Form' . JString::ucfirst($entity, '_') . JString::ucfirst($type, '_');
152 
153         if (class_exists($class))
154         {
155             return $class;
156         }
157         elseif (class_exists($altClass))
158         {
159             return $altClass;
160         }
161 
162         // Get the field search path array.
163         $paths = self::addPath($entity);
164 
165         // If the type is complex, add the base type to the paths.
166         if ($pos = strpos($type, '_'))
167         {
168             // Add the complex type prefix to the paths.
169             for ($i = 0, $n = count($paths); $i < $n; $i++)
170             {
171                 // Derive the new path.
172                 $path = $paths[$i] . '/' . strtolower(substr($type, 0, $pos));
173 
174                 // If the path does not exist, add it.
175                 if (!in_array($path, $paths))
176                 {
177                     $paths[] = $path;
178                 }
179             }
180 
181             // Break off the end of the complex type.
182             $type = substr($type, $pos + 1);
183         }
184 
185         // Try to find the class file.
186         $type       = strtolower($type) . '.php';
187         $filesystem = FOFPlatform::getInstance()->getIntegrationObject('filesystem');
188 
189         foreach ($paths as $path)
190         {
191             if ($file = $filesystem->pathFind($path, $type))
192             {
193                 require_once $file;
194 
195                 if (class_exists($class))
196                 {
197                     break;
198                 }
199                 elseif (class_exists($altClass))
200                 {
201                     break;
202                 }
203             }
204         }
205 
206         // Check for all if the class exists.
207         if (class_exists($class))
208         {
209             return $class;
210         }
211         elseif (class_exists($altClass))
212         {
213             return $altClass;
214         }
215         else
216         {
217             return false;
218         }
219     }
220 
221     /**
222      * Method to add a path to the list of header include paths.
223      *
224      * @param   mixed  $new  A path or array of paths to add.
225      *
226      * @return  array  The list of paths that have been added.
227      */
228     public static function addHeaderPath($new = null)
229     {
230         return self::addPath('header', $new);
231     }
232 }
233