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

/bonfire/application/core_modules/modulebuilder/controllers/developer.php

https://github.com/tgkelly/Bonfire
PHP | 348 lines | 209 code | 64 blank | 75 comment | 44 complexity | 5be60ae787da60ed89b7c5e7f658f46b MD5 | raw file
  1. <?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
  2. /**
  3. * ModuleBuilder
  4. *
  5. * An easy module generator for the Bonfire project on the CodeIgniter framework
  6. *
  7. * @package ModuleBuilder
  8. * @version 0.5.0
  9. * @author Sean Downey, <sean[at]considerweb.com>
  10. * @copyright Copyright (c) 2011, Sean Downey
  11. * @license http://www.opensource.org/licenses/mit-license.php
  12. * @link http://github.com/seandowney/bonfire_modulebuilder
  13. *
  14. * This code is originally based on Ollie Rattue's http://formigniter.org/ project
  15. */
  16. class Developer extends Admin_Controller {
  17. //---------------------------------------------------------------
  18. public function __construct()
  19. {
  20. parent::__construct();
  21. $this->auth->restrict('Site.Developer.View');
  22. $this->load->library('modulebuilder');
  23. $this->load->config('modulebuilder');
  24. $this->lang->load('modulebuilder');
  25. $this->load->helper('file');
  26. $this->load->dbforge();
  27. $this->options = $this->config->item('modulebuilder');
  28. Assets::add_js($this->load->view('developer/modulebuilder_js', null, true), 'inline');
  29. }
  30. //---------------------------------------------------------------
  31. /*
  32. Method: index()
  33. Displays a list of installed modules with the option to create
  34. a new one.
  35. */
  36. public function index()
  37. {
  38. $modules = module_list(true);
  39. $configs = array();
  40. foreach ($modules as $module)
  41. {
  42. $configs[$module] = module_config($module);
  43. if (!isset($configs[$module]['name']))
  44. {
  45. $configs[$module]['name'] = ucwords($module);
  46. }
  47. }
  48. ksort($configs);
  49. Template::set('modules', $configs);
  50. Template::set('toolbar_title', 'Manage Modules');
  51. Template::render();
  52. }
  53. //--------------------------------------------------------------------
  54. /*
  55. Method: create()
  56. Displays the create a module form.
  57. */
  58. public function create()
  59. {
  60. $this->auth->restrict('Bonfire.Modules.Add');
  61. $hide_form = false;
  62. $this->field_total = $this->input->post('field_total');
  63. $this->field_total = 0;
  64. $last_seg = $this->uri->segment( $this->uri->total_segments() );
  65. if (is_numeric($last_seg))
  66. {
  67. $this->field_total = $last_seg;
  68. }
  69. // validation hasn't been passed
  70. if ($this->validate_form($this->field_total) == FALSE)
  71. {
  72. Template::set('field_total', $this->field_total);
  73. if (!empty($_POST))
  74. {
  75. Template::set('form_error', TRUE);
  76. }
  77. else
  78. {
  79. Template::set('form_error', FALSE);
  80. }
  81. $query = $this->db->select('role_id,role_name')->order_by('role_name')->get('roles');
  82. Template::set('roles', $query->result_array());
  83. Template::set('form_action_options', $this->options['form_action_options']);
  84. Template::set('validation_rules', $this->options['validation_rules']);
  85. Template::set('validation_limits', $this->options['validation_limits']);
  86. Template::set('field_numbers', range(0,20));
  87. Template::set_view('developer/modulebuilder_form');
  88. } else
  89. {
  90. // passed validation proceed to second page
  91. $this->build_module($this->field_total);
  92. Template::set_view('developer/output');
  93. }
  94. Template::set('error', array());
  95. Template::set('toolbar_title', 'Module Builder');
  96. Template::render();
  97. }
  98. //--------------------------------------------------------------------
  99. /*
  100. Method: delete()
  101. Deletes and module and all of it's files.
  102. */
  103. public function delete()
  104. {
  105. $module_name = $this->uri->segment(5);
  106. if (!empty($module_name))
  107. {
  108. $this->auth->restrict('Bonfire.Modules.Delete');
  109. $prefix = $this->db->dbprefix;
  110. $this->db->trans_begin();
  111. // drop the main table
  112. $this->dbforge->drop_table($module_name);
  113. // get any permission ids
  114. $query = $this->db->query('SELECT permission_id FROM '.$prefix.'permissions WHERE name LIKE "'.$module_name.'.%.%"');
  115. if ($query->num_rows() > 0) {
  116. foreach($query->result_array() as $row) {
  117. // undo any permissions that exist
  118. $this->db->where('permission_id',$row['permission_id']);
  119. $this->db->delete($prefix.'permissions');
  120. // and fron the roles as well.
  121. $this->db->where('permission_id',$row['permission_id']);
  122. $this->db->delete($prefix.'role_permissions');
  123. }
  124. }
  125. // drop the schema #
  126. if ($this->db->field_exists(strtolower($module_name).'_version', 'schema_version'))
  127. {
  128. $this->dbforge->drop_column('schema_version',strtolower($module_name).'_version');
  129. }
  130. if ($this->db->trans_status() === FALSE) {
  131. $this->db->trans_rollback();
  132. Template::set_message('We could not delete this module.', $this->db->error, 'error');
  133. } else {
  134. $this->db->trans_commit();
  135. // database was successful in deleting everything. Now try to get rid of the files.
  136. if (delete_files(module_path($module_name), true)) {
  137. @rmdir(module_path($module_name.'/'));
  138. Template::set_message('The module and associated database entries were successfully deleted.', 'success');
  139. Template::redirect(SITE_AREA .'/developer/modulebuilder');
  140. } else {
  141. Template::set_message('The module and associated database entries were successfully deleted, HOWEVER, the module folder and files were not removed. They must be removed manually.', 'info');
  142. }
  143. }
  144. }
  145. Template::render();
  146. }
  147. //--------------------------------------------------------------------
  148. //--------------------------------------------------------------------
  149. // !PRIVATE METHODS
  150. //--------------------------------------------------------------------
  151. /*
  152. Method: validate_form()
  153. Handles the validation of the modulebuilder form.
  154. */
  155. private function validate_form($field_total=0)
  156. {
  157. $this->form_validation->set_rules("contexts_content",'Contexts :: Content',"trim|xss_clean|is_numeric");
  158. $this->form_validation->set_rules("contexts_developer",'Contexts :: Developer',"trim|xss_clean|is_numeric");
  159. $this->form_validation->set_rules("contexts_public",'Contexts :: Public',"trim|xss_clean|is_numeric");
  160. $this->form_validation->set_rules("contexts_reports",'Contexts :: Reports',"trim|xss_clean|is_numeric");
  161. $this->form_validation->set_rules("contexts_settings",'Contexts :: Settings',"trim|xss_clean|is_numeric");
  162. $this->form_validation->set_rules("db_required",'Generate Migration',"trim|xss_clean|is_numeric");
  163. $this->form_validation->set_rules("form_action_create",'Form Actions :: View',"trim|xss_clean|is_numeric");
  164. $this->form_validation->set_rules("form_action_delete",'Form Actions :: View',"trim|xss_clean|is_numeric");
  165. $this->form_validation->set_rules("form_action_edit",'Form Actions :: View',"trim|xss_clean|is_numeric");
  166. $this->form_validation->set_rules("form_action_view",'Form Actions :: List',"trim|xss_clean|is_numeric");
  167. $this->form_validation->set_rules("form_error_delimiters",'Form Error Delimiters',"required|trim|xss_clean");
  168. $this->form_validation->set_rules("form_input_delimiters",'Form Input Delimiters',"required|trim|xss_clean");
  169. $this->form_validation->set_rules("module_description",'Module Description',"trim|required|xss_clean");
  170. $this->form_validation->set_rules("module_name",'Module Name',"trim|required|xss_clean|alpha_dash");
  171. $this->form_validation->set_rules("role_id",'Give Role Full Access',"trim|xss_clean|is_numeric");
  172. // no point doing all this checking if we don't want a table
  173. if ($this->input->post('db_required')) {
  174. $this->form_validation->set_rules("primary_key_field",'Primary Key Field',"required|trim|xss_clean|alpha_dash");
  175. $this->form_validation->set_rules("table_name",'Table Name',"trim|required|xss_clean|alpha_dash");
  176. $this->form_validation->set_rules("textarea_editor",'Textarea Editor',"trim|xss_clean|alpha_dash");
  177. for($counter=1; $field_total >= $counter; $counter++)
  178. {
  179. if ($counter != 1) // better to do it this way round as this statement will be fullfilled more than the one below
  180. {
  181. $this->form_validation->set_rules("view_field_label$counter","Label $counter",'trim|xss_clean|alpha_dash');
  182. }
  183. else
  184. {
  185. // the first field always needs to be required i.e. we need to have at least one field in our form
  186. $this->form_validation->set_rules("view_field_label$counter","Label $counter",'trim|required|xss_clean|alpha_dash');
  187. }
  188. $name_required = '';
  189. $label = $this->input->post("view_field_label$counter");
  190. if( !empty($label) )
  191. {
  192. $name_required = 'required|';
  193. }
  194. $this->form_validation->set_rules("view_field_name$counter","Name $counter","trim|".$name_required."callback_no_match[$counter]|xss_clean");
  195. $this->form_validation->set_rules("view_field_type$counter","Field Type $counter","trim|required|xss_clean|alpha");
  196. $this->form_validation->set_rules("db_field_type$counter","DB Field Type $counter","trim|xss_clean|alpha");
  197. // make sure that the length field is required if the DB Field type requires a length
  198. $db_len_required = '';
  199. $field_type = $this->input->post("db_field_type$counter");
  200. if( !empty($label) && !($field_type == 'TEXT'
  201. OR $field_type == 'DATE' OR $field_type == 'TIME' OR $field_type == 'DATETIME'
  202. OR $field_type == 'TIMESTAMP' OR $field_type == 'YEAR'
  203. OR $field_type == 'TINYBLOB' OR $field_type == 'BLOB' OR $field_type == 'MEDIUMBLOB' OR $field_type == 'LONGBLOB') )
  204. {
  205. $db_len_required = 'required|';
  206. }
  207. $this->form_validation->set_rules("db_field_length_value$counter","DB Field Length $counter","trim|".$db_len_required."xss_clean");
  208. $this->form_validation->set_rules('validation_rules'.$counter.'[]',"Validation Rules $counter",'trim|xss_clean');
  209. }
  210. }
  211. return $this->form_validation->run();
  212. }
  213. //--------------------------------------------------------------------
  214. /*
  215. Method: build_module()
  216. Handles the heavy-lifting of building a module from ther user's specs.
  217. */
  218. private function build_module($field_total=0)
  219. {
  220. $module_name = $this->input->post('module_name');
  221. $table_name = str_replace(' ','_',strtolower($this->input->post('table_name')));
  222. $contexts = $this->input->post('contexts');
  223. $action_names = $this->input->post('form_action');
  224. $module_description = $this->input->post('module_description');
  225. $role_id = $this->input->post('role_id');
  226. $db_required = isset($_POST['db_required']) ? TRUE : FALSE;
  227. $primary_key_field = $this->input->post('primary_key_field');
  228. if( $primary_key_field == '') {
  229. $primary_key_field = $this->options['primary_key_field'];
  230. }
  231. $primary_key_field = strtolower($primary_key_field);
  232. $form_input_delimiters = explode(',', $this->input->post('form_input_delimiters'));
  233. if( !is_array($form_input_delimiters) OR count($form_input_delimiters) != 2) {
  234. $form_input_delimiters = $this->options['form_input_delimiters'];
  235. }
  236. $form_error_delimiters = explode(',', $this->input->post('form_error_delimiters'));
  237. if( !is_array($form_error_delimiters) OR count($form_error_delimiters) != 2) {
  238. $form_error_delimiters = $this->options['$form_error_delimiters'];
  239. }
  240. $file_data = $this->modulebuilder->build_files($field_total, $module_name, $contexts, $action_names, $primary_key_field, $db_required, $form_input_delimiters, $form_error_delimiters, $module_description, $role_id, $table_name);
  241. // make the variables available to the view file
  242. $data['module_name'] = $module_name;
  243. $data['module_name_lower'] = strtolower($module_name);
  244. $data['controller_name'] = $module_name;
  245. $data['table_name'] = empty($table_name) ? $module_name : $table_name;
  246. $data = $data + $file_data;
  247. Template::set($data);
  248. }
  249. //--------------------------------------------------------------------
  250. /** Custom Form Validation Callback Rule
  251. *
  252. * Checks that one field doesn't match all the others.
  253. * This code is not really portable. Would of been nice to create a rule that accepted an array
  254. *
  255. * @access public
  256. * @param string
  257. * @param fields array
  258. * @return bool
  259. */
  260. function no_match($str, $fieldno)
  261. {
  262. for($counter=1; $this->field_total >= $counter; $counter++)
  263. {
  264. // nothing has been entered into this field so we don't need to check
  265. // or the field being checked is the same as the field we are checking from
  266. if ($_POST["view_field_name$counter"] == '' || $fieldno == $counter)
  267. {
  268. continue;
  269. }
  270. if ($str == $_POST["view_field_name{$counter}"])
  271. {
  272. $this->form_validation->set_message('no_match', "Field names ($fieldno & $counter) must be unique!");
  273. return FALSE;
  274. }
  275. }
  276. return TRUE;
  277. }
  278. //--------------------------------------------------------------------
  279. }