PageRenderTime 23ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/atk4/lib/View/CRUD.php

https://github.com/mahimarathore/mahi
PHP | 478 lines | 208 code | 63 blank | 207 comment | 31 complexity | 315cea6b3f67ba948a86166293aff329 MD5 | raw file
Possible License(s): AGPL-3.0, MPL-2.0-no-copyleft-exception
  1. <?php // vim:ts=4:sw=4:et:fdm=marker
  2. /**
  3. ==ATK4===================================================
  4. This file is part of Agile Toolkit 4
  5. http://agiletoolkit.org/
  6. (c) 2008-2013 Agile Toolkit Limited <info@agiletoolkit.org>
  7. Distributed under Affero General Public License v3 and
  8. commercial license.
  9. See LICENSE or LICENSE_COM for more information
  10. =====================================================ATK4=*/
  11. /**
  12. * CRUD stands for Create, Read, Update and Delete. This view combines
  13. * both "Grid", "Form" and "VirtualPage" to bring you a seamless editing
  14. * control. You would need to supply a model.
  15. *
  16. * IMPORTANT NOTE: While you can disable adding and editing, if you do that
  17. * you must simply use Grid!
  18. *
  19. * @link http://agiletoolkit.org/
  20. */
  21. class View_CRUD extends View
  22. {
  23. /**
  24. * After CRUD is initialized, this will point to a form object IF
  25. * CRUD goes into editing mode. Typically the same code is initialized
  26. * for editing pop-up, but only form is rendered. You can enhance the
  27. * form all you want
  28. *
  29. * IMPORTANT: check isEditing() method
  30. */
  31. public $form=null;
  32. /**
  33. * After CRUD is initialized, this will point do a Grid object, IF
  34. * CRUD is in "read" mode. You can add more columns or actions to the
  35. * grid.
  36. *
  37. * IMPORTANT: check isEditing() method
  38. */
  39. public $grid=null;
  40. /**
  41. * By default, CRUD will simply use "Grid" class, but if you would like
  42. * to use your custom grid class for listing, specify it inside associative
  43. * array as second argument to add()
  44. *
  45. * $this->add('CRUD', array('grid_class'=>'MyGrid'));
  46. */
  47. public $grid_class='Grid';
  48. /**
  49. * By default, CRUD will simply use "Form" class for editing and adding,
  50. * but if you would like to use your custom form, specify it inside
  51. * associative array as second argument to add()
  52. *
  53. * $this->add('CRUD', array('grid_class'=>'MyGrid'));
  54. */
  55. public $form_class='Form';
  56. /**
  57. * Grid will contain an "Add X" button and will allow user to add records
  58. *
  59. * $this->add('CRUD', array('allow_add'=>false')); // to disable
  60. */
  61. protected $allow_add=true;
  62. /**
  63. * Grid will contain "EDIT" button for each row allowing usir to edit
  64. * records
  65. *
  66. * $this->add('CRUD', array('allow_edit'=>false')); // to disable
  67. */
  68. protected $allow_edit=true;
  69. /**
  70. * Grid will contain a "DELETE" button for each row. If you don't want
  71. * thes set this option to false
  72. *
  73. * $this->add('CRUD', array('allow_del'=>false')); // to disable
  74. */
  75. protected $allow_del=true;
  76. /**
  77. * For ->setModel('User'), your add button would contain "Add User". If
  78. * you want add button and frames to use different label, then change
  79. * this property.
  80. *
  81. * If you set this to 'false' then CRUD will not attempt to change
  82. * default label ("Add")
  83. */
  84. public $entity_name=null;
  85. /**
  86. * This points to a Button object, which you can change if you want
  87. * a different label or anything else on it
  88. */
  89. public $add_button;
  90. /**
  91. * VirtualPage object will be used to display popup content. That is to ensure
  92. * that none of your other content you put AROUND the CRUD would mess
  93. * with the forms.
  94. *
  95. * If isEditing() then you can add more stuff on this page, by calling
  96. * virtual_page->getPage()->add('Hello!');
  97. */
  98. public $virtual_page=null;
  99. /**
  100. * When clicking on EDIT or ADD the frameURL is used. If you want to pass
  101. * some arguments to it, put your hash here.
  102. */
  103. public $frame_options=null;
  104. /**
  105. * This is set to ID of the model when are in editing mode. In theory
  106. * this can also be 0, so use is_null()
  107. */
  108. public $id=null;
  109. /**
  110. * {@inheritdoc}
  111. *
  112. * CRUD's init() will create either a grid or form, depending on
  113. * isEditing(). You can then do the necessary changes after
  114. *
  115. * Note, that the form or grid will not be populated until you
  116. * call setModel()
  117. *
  118. * @return void
  119. */
  120. function init()
  121. {
  122. parent::init();
  123. // Virtual Page would receive 3 types of requests - add, delete, edit
  124. $this->virtual_page = $this->add('VirtualPage', array(
  125. 'frame_options'=>$this->frame_options
  126. ));
  127. if ($_GET['edit']) {
  128. $_GET[$this->name.'_id'] = $_GET['edit'];
  129. }
  130. if (isset($_GET[$this->name.'_id'])) {
  131. $this->api->stickyGET($this->name.'_id');
  132. $this->id=$_GET[$this->name.'_id'];
  133. }
  134. if ($this->isEditing()) {
  135. $this->form = $this
  136. ->virtual_page
  137. ->getPage()
  138. ->add($this->form_class);
  139. return;
  140. }
  141. $this->grid=$this->add($this->grid_class);
  142. // Left for compatibility
  143. $this->js('reload', $this->grid->js()->reload());
  144. if ($this->allow_add) {
  145. $this->add_button = $this->grid->addButton('Add');
  146. }
  147. }
  148. /**
  149. * Returns if CRUD is in editing mode or not. It's preferable over
  150. * checking if($grid->form)
  151. *
  152. * @param string $mode Specify which editing mode you expect
  153. *
  154. * @return boolean true if editing.
  155. */
  156. function isEditing($mode = null)
  157. {
  158. $page_mode = $this->virtual_page->isActive();
  159. // Requested edit, but not allowed
  160. if ($page_mode=='edit' && !$this->allow_edit) {
  161. throw $this->exception('Editing is not allowed');
  162. }
  163. // Requested add but not allowed
  164. if ($page_mode=='add' && !$this->allow_add) {
  165. throw $this->exception('Adding is not allowed');
  166. }
  167. // Request matched argument exactly
  168. if (!is_null($mode)) {
  169. return $mode === $page_mode;
  170. }
  171. // Argument was blank, then edit/add is OK
  172. return $page_mode=='edit' || $page_mode=='add';
  173. }
  174. /**
  175. * Obsolete YEEE
  176. *
  177. * @obsolete
  178. */
  179. function setController($controller){
  180. if($this->form){
  181. $this->form->setController($controller);
  182. $this->form->addSubmit('Save');
  183. }elseif($this->grid){
  184. $this->grid->setController($controller);
  185. }
  186. $this->initComponents();
  187. }
  188. /**
  189. * Assign model to your CRUD and specify list of fields to use from model
  190. *
  191. * {@inheritdoc}
  192. *
  193. * @param string|object $model Same as parent
  194. * @param array $fields Specify list of fields for form and grid
  195. * @param array $grid_fields Overide list of fields for the grid
  196. *
  197. * @return AbstractModel $model
  198. */
  199. function setModel($model, $fields = null, $grid_fields = null)
  200. {
  201. $model=parent::setModel($model);
  202. if ($this->entity_name === null) {
  203. // Calculates entity name
  204. $this->entity_name = str_replace(
  205. array('Model_', '_'),
  206. array('', ' '),
  207. get_class($this->model)
  208. );
  209. }
  210. if (!$this->isEditing()) {
  211. $this->configureGrid(is_null($grid_fields)?$fields:$grid_fields);
  212. }
  213. if ($this->allow_add) {
  214. if ($this->configureAdd($fields)) {
  215. return $model;
  216. }
  217. }
  218. if ($this->allow_edit) {
  219. if ($this->configureEdit($fields)) {
  220. return $model;
  221. }
  222. }
  223. if ($this->allow_del) {
  224. $this->configureDel();
  225. }
  226. return $model;
  227. }
  228. /**
  229. * Adds expander to the crud, which edits references under the specified
  230. * name. Returns object of nested CRUD when active, or null
  231. *
  232. * The format of $options is the following:
  233. * array (
  234. * 'view_class' => 'CRUD', // Which View to use inside expander
  235. * 'view_options' => .. // Second arg when adding view.
  236. * 'fields' => array() // Used as second argument for setModel()
  237. * 'extra_fields' => array() // Third arguments to setModel() used by CRUDs
  238. * 'label'=> 'Click Me' // Label for a button inside a grid
  239. * )
  240. *
  241. * @param string $name Name of the reference. If you leave blank adds all
  242. * @param array $options Customizations, see above
  243. *
  244. * @return View_CRUD|null Returns crud object, when expanded page is rendered
  245. */
  246. function addRef($name, $options = array())
  247. {
  248. if (!$this->model) {
  249. throw $this->exception('Must set CRUD model first');
  250. }
  251. if (!is_array($options)) {
  252. throw $this->exception('Must be array');
  253. }
  254. if ($this->isEditing('ex_'.$name)) {
  255. if ($_GET['id']) {
  256. $this->id = $_GET[$this->name.'_id'] = $_GET['id'];
  257. $this->api->stickyGET($this->name.'_id');
  258. }
  259. $view_class = (is_null($options['view_class']))?
  260. get_class($this):
  261. $options['view_class'];
  262. $subview=$this->virtual_page->getPage()->add(
  263. $view_class,
  264. $options['view_options']
  265. );
  266. $subview->setModel(
  267. $this->model->load($this->id)->ref($name),
  268. $options['fields'],
  269. $options['extra_fields']
  270. );
  271. return $subview;
  272. }
  273. if ($this->isEditing()) {
  274. return;
  275. }
  276. $this->grid->addColumn('expander', 'ex_'.$name, $options['label']?:$name);
  277. $this->grid->columns['ex_'.$name]['page']
  278. = $this->virtual_page->getURL('ex_'.$name);
  279. }
  280. /**
  281. * Adds button to the crud, which opens a new frame and returns page to
  282. * you. Add anything into the page as you see fit. The ID of the record
  283. * will be inside $crud->id
  284. *
  285. * @param string $name Unique name, also button and title default
  286. * @param array $options Options
  287. *
  288. * @return Page|null Returns object if clicked on popup.
  289. */
  290. function addFrame($name, $options = array())
  291. {
  292. if (!$this->model) {
  293. throw $this->exception('Must set CRUD model first');
  294. }
  295. if (!is_array($options)) {
  296. throw $this->exception('Must be array');
  297. }
  298. if ($this->isEditing('fr_'.$name)) {
  299. if ($_GET['fr_'.$name]) {
  300. $this->id = $_GET[$this->name.'_id'] = $_GET['fr_'.$name];
  301. $this->api->stickyGET($this->name.'_id');
  302. }
  303. return $this->virtual_page->getPage();
  304. }
  305. if ($this->isEditing()) {
  306. return;
  307. }
  308. $this
  309. ->virtual_page
  310. ->addColumn('fr_'.$name, $options['title']?:$name, $options['label'], $this->grid)
  311. ;
  312. }
  313. /**
  314. * Configures necessary components when CRUD is in the adding mode
  315. *
  316. * @param array $fields List of fields for add form
  317. *
  318. * @return void|Model If model, then bail out, no greed needed
  319. */
  320. function configureAdd($fields)
  321. {
  322. // We are actually in the frame!
  323. if ($this->isEditing('add')) {
  324. $m = $this->form->setModel($this->model, $fields);
  325. $this->form->addSubmit('Add');
  326. $this->form->onSubmit(array($this,'formSubmit'));
  327. return $m;
  328. } elseif ($this->isEditing()) return;
  329. // Configure Add Button on Grid and JS
  330. $this->add_button->js('click')->univ()
  331. ->frameURL(
  332. $this->entity_name===false?
  333. 'New Record':
  334. 'Adding new '.$this->entity_name,
  335. $this->virtual_page->getURL('add')
  336. );
  337. if ($this->entity_name !== false) {
  338. $this->add_button->setLabel('Add '.$this->entity_name);
  339. }
  340. }
  341. /**
  342. * Configures necessary components when CRUD is in the editing mode
  343. *
  344. * @param array $fields List of fields for add form
  345. *
  346. * @return void|Model If model, then bail out, no greed needed
  347. */
  348. function configureEdit($fields)
  349. {
  350. // We are actually in the frame!
  351. if ($this->isEditing('edit')) {
  352. $m = $this->form->setModel($this->model, $fields);
  353. $m->load($this->id);
  354. $this->form->addSubmit();
  355. $this->form->onSubmit(array($this,'formSubmit'));
  356. return $m;
  357. } elseif ($this->isEditing()) return;
  358. $this
  359. ->virtual_page
  360. ->addColumn('edit', 'Editing '.$this->entity_name, 'Edit', $this->grid)
  361. ;
  362. }
  363. /**
  364. * Configures grid's model itself
  365. *
  366. * @param array $fields List of fields for grid
  367. *
  368. * @return void
  369. */
  370. function configureGrid($fields)
  371. {
  372. $this->grid->setModel($this->model, $fields);
  373. }
  374. /**
  375. * Configures deleting functionality for grid
  376. *
  377. * @return void
  378. */
  379. function configureDel()
  380. {
  381. $this->grid->addColumn('delete', 'delete');
  382. }
  383. /**
  384. * Called after on post-init hook when form is submitted
  385. *
  386. * @param Form $form Form which was submitted
  387. *
  388. * @return void
  389. */
  390. function formSubmit($form)
  391. {
  392. try {
  393. $form->update();
  394. $self = $this;
  395. $this->api->addHook('pre-render', function () use ($self) {
  396. $self->formSubmitSuccess()->execute();
  397. });
  398. } catch (Exception_ValidityCheck $e) {
  399. $form->displayError($e->getField(), $e->getMessage());
  400. }
  401. }
  402. /**
  403. * Returns JavaScript action which should be executed on form successfull
  404. * submission
  405. *
  406. * @return jQuery_Chain to be executed on successful submit
  407. */
  408. function formSubmitSuccess()
  409. {
  410. return $this->form->js(null, $this->js()->trigger('reload'))
  411. ->univ()->closeDialog();
  412. }
  413. }