NF_AJAX_Controllers_Submission

The Ninja Forms NF AJAX Controllers Submission class.

Defined (1)

The class is defined in the following location(s).

/includes/AJAX/Controllers/Submission.php  
  1. class NF_AJAX_Controllers_Submission extends NF_Abstracts_Controller 
  2. protected $_form_data = array(); 
  3.  
  4. protected $_form_cache = array(); 
  5.  
  6. protected $_preview_data = array(); 
  7.  
  8. protected $_form_id = ''; 
  9.  
  10. public function __construct() 
  11. if( isset( $_POST[ 'nf_resume' ] ) && isset( $_COOKIE[ 'nf_wp_session' ] ) ) { 
  12. add_action( 'ninja_forms_loaded', array( $this, 'resume' ) ); 
  13. return; 
  14.  
  15. if( isset( $_POST['formData'] ) ) { 
  16. $this->_form_data = json_decode( $_POST['formData'], TRUE ); 
  17.  
  18. // php5.2 fallback 
  19. if( ! $this->_form_data ) $this->_form_data = json_decode( stripslashes( $_POST['formData'] ), TRUE ); 
  20.  
  21.  
  22. add_action( 'wp_ajax_nf_ajax_submit', array( $this, 'submit' ) ); 
  23. add_action( 'wp_ajax_nopriv_nf_ajax_submit', array( $this, 'submit' ) ); 
  24.  
  25. add_action( 'wp_ajax_nf_ajax_resume', array( $this, 'resume' ) ); 
  26. add_action( 'wp_ajax_nopriv_nf_ajax_resume', array( $this, 'resume' ) ); 
  27.  
  28. public function submit() 
  29. check_ajax_referer( 'ninja_forms_display_nonce', 'security' ); 
  30.  
  31. register_shutdown_function( array( $this, 'shutdown' ) ); 
  32.  
  33. $this->form_data_check(); 
  34.  
  35. $this->_form_id = $this->_form_data['id']; 
  36.  
  37. if( $this->is_preview() ) { 
  38.  
  39. $this->_form_cache = get_user_option( 'nf_form_preview_' . $this->_form_id ); 
  40.  
  41. if( ! $this->_form_cache ) { 
  42. $this->_errors[ 'preview' ] = __( 'Preview does not exist.', 'ninja-forms' ); 
  43. $this->_respond(); 
  44. } else { 
  45. $this->_form_cache = get_option( 'nf_form_' . $this->_form_id ); 
  46.  
  47. // TODO: Update Conditional Logic to preserve field ID => [ Settings, ID ] structure. 
  48. $this->_form_data = apply_filters( 'ninja_forms_submit_data', $this->_form_data ); 
  49.  
  50. $this->process(); 
  51.  
  52. public function resume() 
  53. $this->_form_data = Ninja_Forms()->session()->get( 'nf_processing_form_data' ); 
  54. $this->_form_cache = Ninja_Forms()->session()->get( 'nf_processing_form_cache' ); 
  55. $this->_data = Ninja_Forms()->session()->get( 'nf_processing_data' ); 
  56. $this->_data[ 'resume' ] = $_POST[ 'nf_resume' ]; 
  57.  
  58. $this->_form_id = $this->_data[ 'form_id' ]; 
  59.  
  60. unset( $this->_data[ 'halt' ] ); 
  61. unset( $this->_data[ 'actions' ][ 'redirect' ] ); 
  62.  
  63. $this->process(); 
  64.  
  65. protected function process() 
  66. // Init Field Merge Tags. 
  67. $field_merge_tags = Ninja_Forms()->merge_tags[ 'fields' ]; 
  68. $field_merge_tags->set_form_id( $this->_form_id ); 
  69.  
  70. // Init Calc Merge Tags. 
  71. $calcs_merge_tags = Ninja_Forms()->merge_tags[ 'calcs' ]; 
  72.  
  73. $form_settings = $this->_form_cache[ 'settings' ]; 
  74. if( ! $form_settings ) { 
  75. $form = Ninja_Forms()->form( $this->_form_id )->get(); 
  76. $form_settings = $form->get_settings(); 
  77.  
  78. $this->_data[ 'form_id' ] = $this->_form_data[ 'form_id' ] = $this->_form_id; 
  79. $this->_data[ 'settings' ] = $form_settings; 
  80. $this->_data[ 'settings' ][ 'is_preview' ] = $this->is_preview(); 
  81. $this->_data[ 'extra' ] = $this->_form_data[ 'extra' ]; 
  82.  
  83. /** 
  84. |-------------------------------------------------------------------------- 
  85. | Fields 
  86. |-------------------------------------------------------------------------- 
  87. */ 
  88.  
  89. $form_fields = Ninja_Forms()->form( $this->_form_id )->get_fields(); 
  90.  
  91. /** 
  92. * The Field Processing Loop. 
  93. * There can only be one! 
  94. * For performance reasons, this should be the only time that the fields array is traversed. 
  95. * Anything needing to loop through fields should integrate here. 
  96. */ 
  97. $validate_fields = apply_filters( 'ninja_forms_validate_fields', true, $this->_data ); 
  98. foreach( $form_fields as $key => $field ) { 
  99.  
  100. if( is_object( $field ) ) { 
  101. $field = array( 
  102. 'id' => $field->get_id(),  
  103. 'settings' => $field->get_settings() 
  104. ); 
  105.  
  106. /** Get the field ID */ 
  107. /** 
  108. * TODO: Refactor data structures to match. 
  109. * Preview: Field IDs are stored as the associated array key. 
  110. * Publish: Field IDs are stored as an array key=>value pair. 
  111. */ 
  112. if( $this->is_preview() ) { 
  113. $field[ 'id' ] = $key; 
  114.  
  115. // Duplicate field ID as single variable for more readable array access. 
  116. $field_id = $field[ 'id' ]; 
  117.  
  118. // Check that the field ID exists in the submitted for data and has a submitted value. 
  119. if( isset( $this->_form_data[ 'fields' ][ $field_id ] ) && isset( $this->_form_data[ 'fields' ][ $field_id ][ 'value' ] ) ) { 
  120. $field[ 'value' ] = $this->_form_data[ 'fields' ][ $field_id ][ 'value' ]; 
  121. } else { 
  122. $field[ 'value' ] = ''; 
  123.  
  124. // Duplicate field value to settings and top level array item for backwards compatible access (ie Save Action). 
  125. $field[ 'settings' ][ 'value' ] = $field[ 'value' ]; 
  126.  
  127. // Duplicate field value to form cache for passing to the action filter. 
  128. $this->_form_cache[ 'fields' ][ $key ][ 'settings' ][ 'value' ] = $this->_form_data[ 'fields' ][ $field_id ][ 'value' ]; 
  129.  
  130. // Duplicate the Field ID for access as a setting. 
  131. $field[ 'settings' ][ 'id' ] = $field[ 'id' ]; 
  132.  
  133. // Combine with submitted data. 
  134. $field = array_merge( $field, $this->_form_data[ 'fields' ][ $field_id ] ); 
  135.  
  136. // Flatten the field array. 
  137. $field = array_merge( $field, $field[ 'settings' ] ); 
  138.  
  139. /** Validate the Field */ 
  140. if( $validate_fields && ! isset( $this->_data[ 'resume' ] ) ) { 
  141. $this->validate_field( $field ); 
  142.  
  143. /** Process the Field */ 
  144. if( ! isset( $this->_data[ 'resume' ] ) ) { 
  145. $this->process_field($field); 
  146. $field = array_merge( $field, $this->_form_data[ 'fields' ][ $field_id ] ); 
  147.  
  148. // Check for field errors after processing. 
  149. if ( isset( $this->_form_data['errors']['fields'][ $field_id ] ) ) { 
  150. $this->_errors['fields'][ $field_id ] = $this->_form_data['errors']['fields'][ $field_id ]; 
  151. $this->_respond(); 
  152.  
  153. /** Populate Field Merge Tag */ 
  154. $field_merge_tags->add_field( $field ); 
  155.  
  156. $this->_data[ 'fields' ][ $field_id ] = $field; 
  157.  
  158. /** 
  159. |-------------------------------------------------------------------------- 
  160. | Calculations 
  161. |-------------------------------------------------------------------------- 
  162. */ 
  163.  
  164. if( isset( $this->_form_cache[ 'settings' ][ 'calculations' ] ) ) { 
  165.  
  166. /** 
  167. * The Calculation Processing Loop 
  168. */ 
  169. foreach( $this->_form_cache[ 'settings' ][ 'calculations' ] as $calc ) { 
  170. $eq = apply_filters( 'ninja_forms_calc_setting', $calc[ 'eq' ] ); 
  171. $dec = ( isset( $calc[ 'dec' ] ) && $calc[ 'dec' ] ) ? $calc[ 'dec' ] : 2; 
  172. $calcs_merge_tags->set_merge_tags( $calc[ 'name' ], $eq, $dec ); 
  173. $this->_data[ 'extra' ][ 'calculations' ][ $calc[ 'name' ] ] = array( 
  174. 'raw' => $calc[ 'eq' ],  
  175. 'parsed' => $eq,  
  176. 'value' => $calcs_merge_tags->get_calc_value( $calc[ 'name' ] ),  
  177. ); 
  178.  
  179.  
  180. /** 
  181. |-------------------------------------------------------------------------- 
  182. | Actions 
  183. |-------------------------------------------------------------------------- 
  184. */ 
  185.  
  186. /** 
  187. * TODO: This section has become convoluted, but will be refactored along with the submission controller. 
  188. */ 
  189.  
  190. if( isset( $this->_data[ 'resume' ] ) && $this->_data[ 'resume' ] ) { 
  191. // On Resume Submission, the action data is loaded form the session. 
  192. // This section intentionally left blank. 
  193. } elseif( ! $this->is_preview() ) { 
  194. // Published forms rely on the Database for the "truth" about Actions. 
  195. $actions = Ninja_Forms()->form($this->_form_id)->get_actions(); 
  196. $this->_form_cache[ 'actions' ] = array(); 
  197. foreach( $actions as $action ) { 
  198. $action_id = $action->get_id(); 
  199. $this->_form_cache[ 'actions' ][ $action_id ] = array( 
  200. 'id' => $action_id,  
  201. 'settings' => $action->get_settings() 
  202. ); 
  203. } else { 
  204. // Previews uses user option for stored data. 
  205. $preview_data = get_user_option( 'nf_form_preview_' . $this->_form_id ); 
  206. $this->_form_cache[ 'actions' ] = $preview_data[ 'actions' ]; 
  207. /** END form cache bypass. */ 
  208.  
  209. // Sort Actions by Timing Order, then by Priority Order. 
  210. usort( $this->_form_cache[ 'actions' ], array( $this, 'sort_form_actions' ) ); 
  211.  
  212. /** 
  213. * Filter Actions so that they can be pragmatically disabled by add-ons. 
  214. * ninja_forms_submission_actions 
  215. * ninja_forms_submission_actions_preview 
  216. */ 
  217. $this->_form_cache[ 'actions' ] = apply_filters( 'ninja_forms_submission_actions', $this->_form_cache[ 'actions' ], $this->_form_cache, $this->_form_data ); 
  218. if( $this->is_preview() ) { 
  219. $this->_form_cache['actions'] = apply_filters('ninja_forms_submission_actions_preview', $this->_form_cache['actions'], $this->_form_cache); 
  220.  
  221. // Initialize the process actions log. 
  222. if( ! isset( $this->_data[ 'processed_actions' ] ) ) $this->_data[ 'processed_actions' ] = array(); 
  223.  
  224. /** 
  225. * The Action Processing Loop 
  226. */ 
  227. foreach( $this->_form_cache[ 'actions' ] as $key => $action ) { 
  228.  
  229. /** Get the action ID */ 
  230. /** 
  231. * TODO: Refactor data structures to match. 
  232. * Preview: Action IDs are stored as the associated array key. 
  233. * Publish: Action IDs are stored as an array key=>value pair. 
  234. */ 
  235. if( $this->is_preview() ) { 
  236. $action[ 'id' ] = $key; 
  237.  
  238. // Duplicate the Action ID for access as a setting. 
  239. $action[ 'settings' ][ 'id' ] = $action[ 'id' ]; 
  240.  
  241. // Duplicate action ID as single variable for more readable array access. 
  242. $action_id = $action[ 'id' ]; 
  243.  
  244. // If an action has already run (ie resume submission), do not re-process. 
  245. if( in_array( $action[ 'id' ], $this->_data[ 'processed_actions' ] ) ) continue; 
  246.  
  247. $action[ 'settings' ] = apply_filters( 'ninja_forms_run_action_settings', $action[ 'settings' ], $this->_form_id, $action[ 'id' ], $this->_form_data['settings'] ); 
  248. if( $this->is_preview() ) { 
  249. $action[ 'settings' ] = apply_filters( 'ninja_forms_run_action_settings_preview', $action[ 'settings' ], $this->_form_id, $action[ 'id' ], $this->_form_data['settings'] ); 
  250.  
  251. if( ! $action[ 'settings' ][ 'active' ] ) continue; 
  252.  
  253. if( ! apply_filters( 'ninja_forms_run_action_type_' . $action[ 'settings' ][ 'type' ], TRUE ) ) continue; 
  254.  
  255. $type = $action[ 'settings' ][ 'type' ]; 
  256.  
  257. if( ! is_string( $type ) ) continue; 
  258.  
  259. $action_class = Ninja_Forms()->actions[ $type ]; 
  260.  
  261. if( ! method_exists( $action_class, 'process' ) ) continue; 
  262.  
  263. if( $data = $action_class->process($action[ 'settings' ], $this->_form_id, $this->_data ) ) { 
  264. $this->_data = apply_filters( 'ninja_forms_post_run_action_type_' . $action[ 'settings' ][ 'type' ], $data ); 
  265.  
  266. // $this->_data[ 'actions' ][ $type ][] = $action; 
  267.  
  268. $this->maybe_halt( $action[ 'id' ] ); 
  269.  
  270. do_action( 'ninja_forms_after_submission', $this->_data ); 
  271.  
  272. $this->_respond(); 
  273.  
  274. protected function validate_field( $field_settings ) 
  275. $field_settings = apply_filters( 'ninja_forms_pre_validate_field_settings', $field_settings ); 
  276.  
  277. if( ! is_string( $field_settings['type'] ) ) return; 
  278.  
  279. $field_class = Ninja_Forms()->fields[ $field_settings['type'] ]; 
  280.  
  281. if( ! method_exists( $field_class, 'validate' ) ) return; 
  282.  
  283. if( $errors = $field_class->validate( $field_settings, $this->_form_data ) ) { 
  284. $field_id = $field_settings[ 'id' ]; 
  285. $this->_errors[ 'fields' ][ $field_id ] = $errors; 
  286. $this->_respond(); 
  287.  
  288. protected function process_field( $field_settings ) 
  289. if( ! is_string( $field_settings['type'] ) ) return; 
  290.  
  291. $field_class = Ninja_Forms()->fields[ $field_settings['type'] ]; 
  292.  
  293. if( ! method_exists( $field_class, 'process' ) ) return; 
  294.  
  295. if( $data = $field_class->process( $field_settings, $this->_form_data ) ) { 
  296. $this->_form_data = $data; 
  297.  
  298. protected function maybe_halt( $action_id ) 
  299. if( isset( $this->_data[ 'errors' ] ) && $this->_data[ 'errors' ] ) { 
  300. $this->_respond(); 
  301.  
  302. if( isset( $this->_data[ 'halt' ] ) && $this->_data[ 'halt' ] ) { 
  303.  
  304. Ninja_Forms()->session()->set( 'nf_processing_data', $this->_data ); 
  305. Ninja_Forms()->session()->set( 'nf_processing_form_data', $this->_form_data ); 
  306. Ninja_Forms()->session()->set( 'nf_processing_form_cache', $this->_form_cache ); 
  307.  
  308. $this->_respond(); 
  309.  
  310. array_push( $this->_data[ 'processed_actions' ], $action_id ); 
  311.  
  312. protected function sort_form_actions( $a, $b ) 
  313. if( is_object( $a ) ) { 
  314. if( ! isset( Ninja_Forms()->actions[ $a->get_setting( 'type' ) ] ) ) return -1; 
  315. $a = Ninja_Forms()->actions[ $a->get_setting( 'type' ) ]; 
  316. } else { 
  317. if( ! isset( Ninja_Forms()->actions[ $a[ 'settings' ][ 'type' ] ] ) ) return -1; 
  318. $a = Ninja_Forms()->actions[ $a[ 'settings' ][ 'type' ] ]; 
  319.  
  320. if( is_object( $b ) ) { 
  321. if( ! isset( Ninja_Forms()->actions[ $b->get_setting( 'type' ) ] ) ) return 1; 
  322. $b = Ninja_Forms()->actions[ $b->get_setting( 'type' ) ]; 
  323. } else { 
  324. if( ! isset( Ninja_Forms()->actions[ $b[ 'settings' ][ 'type' ] ] ) ) return 1; 
  325. $b = Ninja_Forms()->actions[ $b[ 'settings' ][ 'type' ] ]; 
  326.  
  327. if ( $a->get_timing() == $b->get_timing() ) { 
  328. if ( $a->get_priority() == $b->get_priority() ) { 
  329. return 0; 
  330. return ( $a->get_priority() < $b->get_priority() ) ? -1 : 1; 
  331.  
  332. return ( $a->get_timing() < $b->get_timing() ) ? -1 : 1; 
  333.  
  334. public function shutdown() 
  335. $error = error_get_last(); 
  336. if( $error !== NULL && in_array( $error[ 'type' ], array( E_ERROR, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR ) ) ) { 
  337.  
  338. $this->_errors[ 'form' ][ 'last' ] = __( 'The server encountered an error during processing.', 'ninja-forms' ); 
  339.  
  340. if( current_user_can( 'manage_options' ) && isset( $error[ 'message' ] ) ) { 
  341. $this->_errors[ 'form' ][ 'last_admin' ] = '<pre>' . $error[ 'message' ] . '</pre>'; 
  342.  
  343. $this->_errors[ 'last' ] = $error; 
  344. $this->_respond(); 
  345.  
  346. protected function form_data_check() 
  347. if( $this->_form_data ) return; 
  348.  
  349. if( function_exists( 'json_last_error' ) // Function not supported in php5.2 
  350. && function_exists( 'json_last_error_msg' )// Function not supported in php5.2 
  351. && json_last_error() ) { 
  352. $this->_errors[] = json_last_error_msg(); 
  353. } else { 
  354. $this->_errors[] = __( 'An unexpected error occurred.', 'ninja-forms' ); 
  355.  
  356. $this->_respond(); 
  357.  
  358. protected function is_preview() 
  359. if( ! isset( $this->_form_data[ 'settings' ][ 'is_preview' ] ) ) return false; 
  360. return $this->_form_data[ 'settings' ][ 'is_preview' ];