PageRenderTime 70ms CodeModel.GetById 26ms RepoModel.GetById 1ms app.codeStats 0ms

/classes/formo/driver/core.php

https://github.com/Xobb/kohana-formo
PHP | 454 lines | 176 code | 63 blank | 215 comment | 12 complexity | 4b005292d8e6c965589fe7758f44a596 MD5 | raw file
  1. <?php defined('SYSPATH') or die('No direct script access.');
  2. /**
  3. * Abstract Formo_Driver_Core class.
  4. *
  5. * @package Formo
  6. */
  7. abstract class Formo_Driver_Core {
  8. /**
  9. * Decorator object
  10. *
  11. * @var object
  12. * @access protected
  13. */
  14. protected $decorator;
  15. /**
  16. * Field or form object
  17. *
  18. * @var object
  19. * @access protected
  20. */
  21. protected $field;
  22. /**
  23. * The name of the variable passed into the view file
  24. *
  25. * (default value: 'field')
  26. *
  27. * @var string
  28. * @access public
  29. */
  30. public $alias = 'field';
  31. /**
  32. * Indicates whether this kind of field potentially does not have a post value
  33. *
  34. * (default value: FALSE)
  35. *
  36. * @var bool
  37. * @access public
  38. */
  39. public $empty_input = FALSE;
  40. /**
  41. * Indicates whether this kind of field must use the $_FILES array
  42. *
  43. * (default value: FALSE)
  44. *
  45. * @var bool
  46. * @access public
  47. */
  48. public $file = FALSE;
  49. /**
  50. * General factory method
  51. *
  52. * @access public
  53. * @static
  54. * @param mixed Formo_Container $field
  55. * @return void
  56. */
  57. public static function factory(Formo_Container $field)
  58. {
  59. return new Formo_Driver($field);
  60. }
  61. /**
  62. * Populate the field and decorator objects
  63. *
  64. * @access public
  65. * @param mixed Formo_Container $field
  66. * @return void
  67. */
  68. public function __construct(Formo_Container $field)
  69. {
  70. // Load the field instance
  71. $this->field = $field;
  72. // Determine the original decorator type
  73. $type = ($type = $this->field->get('type'))
  74. ? $type
  75. // Fall back on the default form type
  76. : Kohana::config('formo')->type;
  77. $this->decorator($type);
  78. }
  79. /**
  80. * Run methods on the decorator object
  81. *
  82. * @access public
  83. * @param mixed $method
  84. * @param mixed $args
  85. * @return void
  86. */
  87. public function __call($func, $args)
  88. {
  89. // At this point we need to run the method through the decorator
  90. $method = new ReflectionMethod($this->decorator, $func);
  91. return $method->invokeArgs($this->decorator, $args);
  92. }
  93. /**
  94. * Create the decorator instance
  95. *
  96. * @access public
  97. * @param mixed $type
  98. * @return void
  99. */
  100. public function decorator($type)
  101. {
  102. // Make the class name
  103. $class = 'Formo_Decorator_'.ucfirst($type);
  104. // Create the actual decorator object
  105. $this->decorator = new $class($this->field, $this);
  106. }
  107. /**
  108. * Append event takes place after field has been appended
  109. * to its parent
  110. *
  111. * @access public
  112. * @return void
  113. */
  114. public function append()
  115. {
  116. $this->decorator->append();
  117. }
  118. public function set($variable, $value)
  119. {
  120. // If the variable is inside the decorator, set that
  121. if (isset($this->decorator->$variable))
  122. $this->decorator->set($variable, $value);
  123. // Otherwise just set the field value
  124. $this->field->$variable = $value;
  125. return $this->field;
  126. }
  127. public function get($variable, $default, $shallow_look = FALSE)
  128. {
  129. if ($shallow_look !== TRUE AND isset($this->decorator->$variable))
  130. // If the variable is inside the decorator, return that
  131. // and only do so if not doing a shallow look
  132. return $this->decorator->get($variable);
  133. // Otherwise return the field value if it's set, or the default value if it's not
  134. return (isset($this->field->$variable))
  135. ? $this->field->$variable
  136. : $default;
  137. }
  138. /**
  139. * Called at field's construct. Gives driver chance to do stuff
  140. *
  141. * @access public
  142. * @return void
  143. */
  144. public function post_construct(){}
  145. /**
  146. * Called just before running validate()
  147. *
  148. * @access public
  149. * @return void
  150. */
  151. public function pre_validate(){}
  152. /**
  153. * Called just after running validate()
  154. *
  155. * @access public
  156. * @return void
  157. */
  158. public function post_validate(){}
  159. /**
  160. * Run when loading input data
  161. *
  162. * @access public
  163. * @param mixed $value
  164. * @return void
  165. */
  166. public function load($value)
  167. {
  168. // Just set the value to what was passed
  169. $this->val($value);
  170. }
  171. /**
  172. * Retrive a field's value
  173. *
  174. * @access protected
  175. * @return void
  176. */
  177. protected function get_val()
  178. {
  179. $new_value = $this->field->get('new_value');
  180. return (Formo::is_set($new_value) === TRUE)
  181. ? $new_value
  182. : $this->field->get('value');
  183. }
  184. /**
  185. * Set the field's value
  186. *
  187. * @access protected
  188. * @param mixed $value
  189. * @return void
  190. */
  191. protected function set_val($value)
  192. {
  193. $this->field->set('new_value', $value);
  194. }
  195. /**
  196. * Interface for setting, retrieving field's value
  197. *
  198. * @access public
  199. * @param mixed $value. (default: NULL)
  200. * @return void
  201. */
  202. public function val($value = NULL)
  203. {
  204. if (func_num_args() === 0)
  205. return $this->get_val();
  206. // Run pre_filters on the value
  207. $this->run_pre_filters($value);
  208. // Set the value
  209. $this->set_val($value);
  210. // Run ORM methods
  211. $this->set_orm_fields($value);
  212. return $this;
  213. }
  214. /**
  215. * Return the namespaced name
  216. *
  217. * @access public
  218. * @return void
  219. */
  220. public function name()
  221. {
  222. if ( ! $parent = $this->field->parent())
  223. // If there isn't a parent, don't namespace the name
  224. return $this->field->alias();
  225. return $parent->alias().'['.$this->field->alias().']';
  226. }
  227. /**
  228. * Pre-filter field value
  229. *
  230. * @access protected
  231. * @param mixed & $value
  232. * @return void
  233. */
  234. protected function run_pre_filters( & $value)
  235. {
  236. foreach ($this->field->get_filter('pre') as $filter)
  237. {
  238. // Resolve pseudo args
  239. $this->field->pseudo_args($filter->args, array(':value' => $value));
  240. // Run the filters
  241. $value = $filter->execute();
  242. }
  243. }
  244. /**
  245. * Make ORM field values match Formo field values
  246. *
  247. * @access protected
  248. * @param mixed $value
  249. * @return void
  250. */
  251. protected function set_orm_fields($value)
  252. {
  253. if ($orm = $this->field->model(TRUE))
  254. {
  255. $orm->set_field($this->field, $value);
  256. }
  257. }
  258. /**
  259. * Make every option an array of options
  260. *
  261. * @access public
  262. * @param mixed $options
  263. * @return void
  264. */
  265. public function set_options($options)
  266. {
  267. // Create the new array
  268. $array = array();
  269. foreach ($options as $alias => $value)
  270. {
  271. $array[$alias] = ( ! is_array($value))
  272. // Make the value part of an array
  273. ? array('value' => $value)
  274. : $value;
  275. }
  276. return $array;
  277. }
  278. /**
  279. * Run a method through the orm driver
  280. *
  281. * @access public
  282. * @param mixed $method
  283. * @return void
  284. */
  285. public function orm($method)
  286. {
  287. $args = array_slice(func_get_args(), 1);
  288. return call_user_func_array(array($this->field->orm_driver(), $method), $args);
  289. }
  290. /**
  291. * Runs just prior to rendering a form/field
  292. *
  293. * @access public
  294. * @return void
  295. */
  296. public function pre_render()
  297. {
  298. if (isset($this->field->orm))
  299. {
  300. $this->field->orm_driver()->pre_render();
  301. }
  302. $this->decorator->pre_render();
  303. return $this->field;
  304. }
  305. /**
  306. * Render the field
  307. *
  308. * @access public
  309. * @return void
  310. */
  311. public function render()
  312. {
  313. // First run and do any pre_render stuff
  314. $this->pre_render();
  315. return $this->decorator->render();
  316. }
  317. /**
  318. * Run when open is called on the decorator
  319. *
  320. * @access public
  321. * @return void
  322. */
  323. public function open()
  324. {
  325. // First run and do any pre_render stuff
  326. $this->pre_render();
  327. return $this->decorator->open();
  328. }
  329. /**
  330. * Generate a view from a field or form object
  331. *
  332. * @access public
  333. * @return void
  334. */
  335. public function generate($view_file = FALSE, $view_prefix = NULL)
  336. {
  337. if ($this->field->get('render', NULL) === FALSE)
  338. return;
  339. // First run and do any pre_render stuff
  340. $this->pre_render();
  341. // Prefix acts as a templating system for views
  342. $prefix = $this->get_view_prefix($view_prefix);
  343. // Determine the view file
  344. $view = $this->get_view($view_file);
  345. // Skip the prefix if view prefix is FALSE
  346. $skip_prefix = $view_prefix === FALSE;
  347. return $this->decorator->generate($view, $prefix);
  348. }
  349. protected function get_view($view = FALSE)
  350. {
  351. // The defined view file takes precendence over the default one
  352. // and the parameter passed into generate() takes first precedence
  353. return ($view !== FALSE)
  354. // Always choose the passed view if it exists
  355. ? $view
  356. // Next look for the field-level view
  357. : ($view = $this->field->get('view'))
  358. ? $view
  359. : $this->view;
  360. }
  361. protected function get_view_prefix($prefix = NULL)
  362. {
  363. // If the specified prefix is FALSE, no prefix
  364. if ($prefix === FALSE)
  365. return FALSE;
  366. // If the prefix was specified, use it
  367. if ($prefix !== NULL)
  368. return rtrim($prefix, '/');
  369. // Find the appropriate view_prefix
  370. $prefix = $this->field->get('view_prefix', NULL);
  371. if ($prefix === NULL)
  372. {
  373. $prefix = ($parent = $this->field->parent())
  374. ? $parent->get('view_prefix', NULL)
  375. : NULL;
  376. }
  377. // If prefix is still set to NULL and config file has one defined, use the config prefix
  378. if ($prefix === NULL AND $_prefix = Kohana::config('formo')->view_prefix)
  379. {
  380. $prefix = $_prefix;
  381. }
  382. return $prefix;
  383. }
  384. public function not_empty()
  385. {
  386. $new_value = $this->field->get('new_value');
  387. if (Formo::is_set($new_value) === FALSE AND ! $this->field->get('value'))
  388. return FALSE;
  389. return (bool) $new_value;
  390. }
  391. }