PageRenderTime 54ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/handlers/class.atkattributeedithandler.inc

https://github.com/ibuildingsnl/ATK
PHP | 600 lines | 347 code | 83 blank | 170 comment | 47 complexity | cad90b1cbe45a032d72311025888f4b8 MD5 | raw file
Possible License(s): LGPL-2.0, LGPL-2.1, MPL-2.0-no-copyleft-exception, LGPL-3.0
  1. <?php
  2. /**
  3. * This file is part of the Ibuildings E-business Platform.
  4. * Detailed copyright and licensing information can be found
  5. * in the doc/COPYRIGHT and doc/LICENSE files which should be
  6. * included in the distribution.
  7. *
  8. * @package atk
  9. * @subpackage handlers
  10. *
  11. * @author Dennis Luitwieler <dennis@ibuildings.nl>
  12. *
  13. * @copyright (c) 2007 Ibuildings.nl BV
  14. * @license see doc/LICENSE
  15. *
  16. * @version $Revision: 6310 $
  17. * $Id$
  18. */
  19. atkimport("atk.handlers.atkactionhandler");
  20. /**
  21. * Some defines
  22. * @access private
  23. */
  24. define("ATTRIBUTEEDIT_ERROR_DEFAULT", 1);
  25. define("ATTRIBUTEEDIT_ERROR_UPDATE", 2);
  26. define("ATTRIBUTEEDIT_ERROR_NO_SELECTOR_SET", 4);
  27. define("ATTRIBUTEEDIT_ERROR_VALIDATE", 8);
  28. /**
  29. * Handler for the 'attributeedit' action of a node. It shows a dialog for altering the value of
  30. * a selectable attribute for multiple records at the same time.
  31. *
  32. * This handler only supports dialogs.
  33. *
  34. * @author Dennis Luitwieler <dennis@ibuildings.nl>
  35. * @package atk
  36. * @subpackage handlers
  37. *
  38. */
  39. class atkAttributeEditHandler extends atkActionHandler
  40. {
  41. var $m_processUrl = null;
  42. var $m_masterNode = null;
  43. /**
  44. * Set the maste node
  45. *
  46. * @param atkNode $node The master node
  47. */
  48. function setMasterNode($node)
  49. {
  50. $this->m_masterNode = $node;
  51. }
  52. /**
  53. * The action method.
  54. */
  55. function action_attributeedit()
  56. {
  57. if ($this->m_masterNode == null)
  58. {
  59. $this->m_masterNode = $this->m_node;
  60. }
  61. $this->setRenderMode('dialog');
  62. if ($this->m_partial == 'process')
  63. {
  64. $this->handleProcess();
  65. }
  66. elseif ($this->m_partial == 'refreshvaluefield')
  67. {
  68. $this->handleRefreshValuesField();
  69. }
  70. else
  71. {
  72. $atkselector = $this->getSelector();
  73. if (!isset($atkselector) || $atkselector=="")
  74. {
  75. $this->handleError(ATTRIBUTEEDIT_ERROR_NO_SELECTOR_SET, null, false);
  76. }
  77. else
  78. {
  79. $this->handleDialog();
  80. }
  81. }
  82. }
  83. /**
  84. * Get the atkselector from the postvars.
  85. *
  86. * The atkselector could be prefixed, depending on the page where we come
  87. * from. From the admin page it will be prefixed with the formname, from the
  88. * attributeedit dialog, it will not be prefixed anymore.
  89. *
  90. * @return Array
  91. */
  92. function getSelector()
  93. {
  94. // The selector should be in the atkselector postvar
  95. return $this->m_node->m_postvars['atkselector'];
  96. }
  97. /**
  98. * Handle dialog partial.
  99. */
  100. function handleDialog()
  101. {
  102. $page = &$this->getPage();
  103. $result = $this->invoke('attributeEditPage');
  104. $page->addContent($result);
  105. }
  106. /**
  107. * Handle process partial.
  108. */
  109. function handleProcess()
  110. {
  111. $node = &$this->m_node;
  112. $page = &$this->getPage();
  113. $atkselector = $this->getSelector();
  114. if (!isset($atkselector) || count($atkselector)==0)
  115. {
  116. $this->handleError(ATTRIBUTEEDIT_ERROR_NO_SELECTOR_SET);
  117. return;
  118. }
  119. $attributename = $node->m_postvars["attributename"];
  120. $attributevalue = $node->m_postvars[$attributename];
  121. $attribute = $node->getAttribute($attributename);
  122. /** check if input is correct ... */
  123. if (!is_object($attribute) || empty($attributename))
  124. {
  125. $this->handleError(ATTRIBUTEEDIT_ERROR_DEFAULT);
  126. return;
  127. }
  128. // All updates and validates will be successfully executed, until proven otherwise
  129. $validate = true;
  130. $success = true;
  131. foreach ($atkselector as $selector)
  132. {
  133. list($rec) = $node->selectDb($selector, "", "", "", array($attributename));
  134. $rec[$attributename] = $attribute->fetchValue($node->m_postvars);
  135. // Get all the attributes we are NOT changing.
  136. $ignoreList = $this->getIgnoreList($attributename);
  137. // Try to validate the new record.
  138. if (!$node->validate($rec, 'edit', $ignoreList))
  139. {
  140. $validate = false;
  141. break;
  142. }
  143. // If the validation succeeded, we will get here and try to perform the update.
  144. if (!$node->updateDb($rec, false, "", array($attributename)))
  145. {
  146. $success = false;
  147. triggerError($rec, $attributename, $node->getDb()->getErrorType(), $node->getDb()->getErrorMsg());
  148. break;
  149. }
  150. }
  151. // on succes, commit the changes and refresh the page where this dialog was initiated.
  152. if ($validate && $success)
  153. {
  154. $node->getDb()->commit();
  155. $content = "<script type=\"text/javascript\">document.location.href = document.location.href;</script>";
  156. $page->addContent($content);
  157. return;
  158. }
  159. // On validation error, show a validation error message.
  160. if (!$validate)
  161. {
  162. $this->handleError(ATTRIBUTEEDIT_ERROR_VALIDATE, $rec, true);
  163. return;
  164. }
  165. // On failure, do a rollback (if the db supports it) and show an error page.
  166. $node->getDb()->rollback();
  167. $this->handleError(ATTRIBUTEEDIT_ERROR_UPDATE, $rec, true);
  168. }
  169. /**
  170. * Handle errors of different types.
  171. *
  172. * @param int $error The AttributeEditHandler error type.
  173. * @param array $record The record
  174. * @param bool $reload Reload the page?
  175. */
  176. function handleError($error, $record=null, $reload=false)
  177. {
  178. atkimport('atk.ui.atkdialog');
  179. $this->registerExternalFiles();
  180. $content = $this->getErrorPage($error, $record);
  181. $page = &$this->getPage();
  182. if (!$reload)
  183. {
  184. $page->addContent($content);
  185. }
  186. else
  187. {
  188. $script = atkDialog::getUpdateCall($content, false);
  189. $page->register_loadscript($script);
  190. }
  191. }
  192. /**
  193. * Get a page indicating an error has occurred.
  194. *
  195. * @param Int $error
  196. * @param array $record The record
  197. * @param String $customerror
  198. * @return String HTML Error page
  199. */
  200. function getErrorPage($error, $record=null, $customerror='')
  201. {
  202. $errortext = '';
  203. if ($customerror != '')
  204. {
  205. $errortext = $customerror;
  206. }
  207. elseif ($error == ATTRIBUTEEDIT_ERROR_UPDATE)
  208. {
  209. $errortext = $this->m_node->text('error_attributeedit_update');
  210. }
  211. elseif ($error == ATTRIBUTEEDIT_ERROR_NO_SELECTOR_SET)
  212. {
  213. $errortext = $this->m_node->text("error_attributeedit_noselectorset");
  214. }
  215. elseif ($error == ATTRIBUTEEDIT_ERROR_VALIDATE)
  216. {
  217. $errortext = $this->m_node->text("error_attributeedit_validationfailed");
  218. }
  219. else // Other errors
  220. {
  221. $errortext = $this->m_node->text('error_attributeedit_default');
  222. }
  223. $errormsg = '';
  224. if (isset($record) && isset($record['atkerror']))
  225. {
  226. $errormsg = $record['atkerror']['attrib_name'].': '.$record['atkerror']['msg'].'&nbsp;';
  227. }
  228. $ui = &$this->m_node->getUi();
  229. atkimport('atk.ui.atkdialog');
  230. $params = array();
  231. $params["content"] = "<b>".$errortext."</b><br />";
  232. $params["content"].= $errormsg;
  233. $params["buttons"][] = '<input type="button" class="btn_cancel" value="'.$this->m_node->text('close').'" onClick="'.atkDialog::getCloseCall().'" />';
  234. $content = $ui->renderAction("attributeedit", $params);
  235. $params = array();
  236. $params["title"] = $this->m_node->actionTitle('attributeedit');
  237. $params["content"] = $content;
  238. $content = $ui->renderDialog($params);
  239. return $content;
  240. }
  241. /**
  242. * AttributeEdit page.
  243. *
  244. * @return String The attribute edit page
  245. */
  246. function attributeEditPage()
  247. {
  248. return $this->getAttributeEditPage();
  249. }
  250. /**
  251. * Returns the attributeEdit page contents.
  252. *
  253. * @return string attributeEdit page contents
  254. */
  255. function getAttributeEditPage()
  256. {
  257. $url = $this->getProcessUrl();
  258. $controller = &atkController::getInstance();
  259. $this->registerExternalFiles();
  260. $params = array();
  261. $params["formstart"] = $this->getFormStart();
  262. $params["formend"] = '</form>';
  263. $params["content"] = $this->getContent();
  264. $params["buttons"][] = $controller->getDialogButton('save', $this->m_node->text('update_value'), $url);
  265. $params["buttons"][] = $controller->getDialogButton('cancel');
  266. return $this->renderAttributeEditPage($params);
  267. }
  268. /**
  269. * Register external files
  270. *
  271. */
  272. function registerExternalFiles()
  273. {
  274. $page = &$this->getPage();
  275. $ui = &$this->getUi();
  276. $page->register_script(atkconfig("atkroot")."atk/javascript/tools.js");
  277. $page->register_script(atkconfig('atkroot').'atk/javascript/class.atkattributeedithandler.js');
  278. $page->register_style($ui->stylePath("style.css"));
  279. }
  280. /**
  281. * Render the add or copy page using the given parameters.
  282. *
  283. * @param array $params parameters
  284. * @return string rendered page
  285. */
  286. function renderAttributeEditPage($params)
  287. {
  288. $node = &$this->m_node;
  289. $ui = &$node->getUi();
  290. $output = $ui->renderAction("add", $params);
  291. $this->addRenderBoxVar("title", $node->actionTitle('addorcopy'));
  292. $this->addRenderBoxVar("content", $output);
  293. $total = $ui->renderDialog($this->m_renderBoxVars);
  294. return $total;
  295. }
  296. /**
  297. * Returns the attributeEdit page contents.
  298. *
  299. * @return string attributeEdit page contents
  300. */
  301. function getContent()
  302. {
  303. $content = '
  304. <div id="dialogcontent">' .
  305. $this->_getDropDownAttributes() .
  306. '<br />
  307. <div id="selectedvaluediv">' .
  308. $this->_getDropDownValues() .
  309. '</div>
  310. </div>';
  311. return $content;
  312. }
  313. /**
  314. * Get dropdown attributes
  315. *
  316. * @param string $selectedAttribute
  317. * @return String Dropdown with attributenames
  318. */
  319. function _getDropDownAttributes($selectedAttribute="")
  320. {
  321. $fieldprefix = $this->m_node->m_postvars['atkfieldprefix'];
  322. if ($fieldprefix == '') $fieldprefix = $this->m_node->getEditFieldPrefix();
  323. $attributes = $this->getSupportedAttributes();
  324. $attr = null;
  325. // Select the first attribute if none is selected
  326. if ($selectedAttribute=="")
  327. {
  328. // select the first (if available)
  329. $record['attributename'] = isset($attributes[0]) ? $attributes[0]->fieldName() : null;
  330. }
  331. else
  332. {
  333. $record['attributename'] = $selectedAttribute;
  334. }
  335. // Create options and values
  336. foreach ($attributes as $attribute)
  337. {
  338. $options[] = $this->m_node->text($attribute->label($record));
  339. $values[] = $attribute->fieldName();
  340. }
  341. $list = &new atkListAttribute('attributename', $options, $values);
  342. $list->addFlag(AF_LIST_NO_NULL_ITEM);
  343. $list->m_ownerInstance = &$this->m_node;
  344. $list->addOnChangeHandler($this->onChange());
  345. return $list->edit($record,$fieldprefix);
  346. }
  347. /**
  348. * Return the onchange code
  349. *
  350. * @return String The onchange javascript code
  351. */
  352. function onChange()
  353. {
  354. $url = partial_url($this->m_masterNode->atkNodeType(), 'attributeedit', 'refreshvaluefield');
  355. $script = "
  356. ATK.AttributeEditHandler.refreshvalues('$url');
  357. ";
  358. return $script;
  359. }
  360. /**
  361. * Get the dropdown with the possible values for
  362. * the selected attribute.
  363. *
  364. * @param String $selectedAttribute
  365. * @return unknown
  366. */
  367. function _getDropDownValues($selectedAttribute="")
  368. {
  369. $fieldprefix = $this->m_node->m_postvars['atkfieldprefix'];
  370. $attr = null;
  371. // Select the first attribute if none is selected
  372. if ($selectedAttribute=="")
  373. {
  374. // get first attribute
  375. list($attr) = $this->getSupportedAttributes();
  376. }
  377. else
  378. {
  379. $attr = &$this->m_node->getAttribute($selectedAttribute);
  380. }
  381. if (is_object($attr))
  382. {
  383. $record[$attr->fieldName()] = $this->m_node->m_postvars[$attr->fieldName()];
  384. return $attr->edit($record, $fieldprefix, 'edit');
  385. }
  386. return "";
  387. }
  388. /**
  389. * Get the supported attributes.
  390. *
  391. * If no supported attributes were set, ATK determines them by itself.
  392. *
  393. * @return array Array with attribute objects
  394. */
  395. function getSupportedAttributes()
  396. {
  397. $supported = array();
  398. if (method_exists($this->m_node, 'getAttributeEditSupportedAttributes'))
  399. {
  400. $supported_attributes = $this->m_node->getAttributeEditSupportedAttributes();
  401. if (isset($supported_attributes) && is_array($supported_attributes))
  402. {
  403. foreach ($supported_attributes as $attribname)
  404. {
  405. $attr = $this->m_node->getAttribute($attribname);
  406. if (is_object($attr))
  407. $supported[] = $attr;
  408. }
  409. }
  410. return $supported;
  411. }
  412. // We let ATK determine the available attributes.
  413. $attributes = $this->m_node->getAttributes();
  414. // We do not need certain attributes.
  415. foreach ($attributes as $index=>$attr)
  416. {
  417. // Attributes without labels will not be selectable.
  418. if ($attr->hasFlag(AF_NO_LABEL) || $attr->hasFlag(AF_BLANK_LABEL))
  419. continue;
  420. // Hidden attributes will not be selectable
  421. if ($attr->hasFlag(AF_HIDE) || $attr->hasFlag(AF_HIDE_EDIT))
  422. continue;
  423. // You cannot give multiple records a value for a field that should be unique.
  424. $atkselector = $this->getSelector();
  425. if (isset($atkselector) && count($atkselector)>1 && $attr->hasFlag(AF_UNIQUE))
  426. continue;
  427. // You cannot update readonly fields
  428. if ($attr->hasFlag(AF_READONLY) || $attr->hasFlag(AF_READONLY_EDIT))
  429. continue;
  430. // We do not support manytomany relations (for now...).
  431. if (is_a($attr, 'atkmanytomanyrelation'))
  432. continue;
  433. $supported[] = $attr;
  434. }
  435. return $supported;
  436. }
  437. /**
  438. * Get a list of attributenames that we can ignore (i.e. when calling
  439. * validate() on a node.)
  440. *
  441. * @param String $selectedattributename
  442. * @return Array A list of attributenames.
  443. */
  444. function getIgnoreList($selectedattributename)
  445. {
  446. $attributes = $this->m_node->getAttributes();
  447. $attribnames = array();
  448. foreach ($attributes as $attr)
  449. {
  450. $attribnames[] = $attr->fieldName();
  451. }
  452. // remove the selected attribute from all the available attributes,
  453. // and we have a list of attributes that we can ignore.
  454. return array_diff($attribnames, array($selectedattributename));
  455. }
  456. /**
  457. * Returns the form start.
  458. *
  459. * @return string Html form start
  460. */
  461. function getFormStart()
  462. {
  463. $controller = &atkcontroller::getInstance();
  464. $controller->setNode($this->m_node);
  465. $formstart = '<form id="dialogform" name="dialogform" action="'.$controller->getPhpFile().'?'.SID.'" method="post">';
  466. $atkselector = $this->getSelector();
  467. if (isset($atkselector))
  468. {
  469. foreach ($atkselector as &$selector)
  470. {
  471. $formstart.= '<input type="hidden" id="atkselector[]" name="atkselector[]" value="'.$selector.'">';
  472. }
  473. }
  474. return $formstart;
  475. }
  476. /**
  477. * Handle refresh values
  478. *
  479. */
  480. function handleRefreshValuesField()
  481. {
  482. $page = &$this->getPage();
  483. atkimport('atk.utils.atkjson');
  484. // get selected attribute
  485. $selectedattribute = $this->m_node->m_postvars["attributename"];
  486. $field = $this->_getDropDownValues($selectedattribute);
  487. $keys = implode(',', array_keys($this->m_node->m_postvars));
  488. $content = "<script type=\"text/javascript\">$('selectedvaluediv').innerHTML = ".atkJSON::encode($field)."</script>";
  489. $page->addContent($content);
  490. }
  491. /**
  492. * Returns the process URL.
  493. *
  494. * @return string process URL
  495. */
  496. function getProcessUrl()
  497. {
  498. if ($this->m_processUrl != null)
  499. {
  500. return $this->m_processUrl;
  501. }
  502. else
  503. {
  504. return partial_url($this->m_masterNode->atkNodeType(), 'attributeedit', 'process');
  505. }
  506. }
  507. /**
  508. * Override the default process URL.
  509. *
  510. * @param string $url process URL
  511. */
  512. function setProcessUrl($url)
  513. {
  514. $this->m_processUrl = $url;
  515. }
  516. }
  517. ?>