Source for file datamanager.php

Documentation is available at datamanager.php

  1. <?php
  2.  
  3. /**
  4. * @package midcom.helper.datamanager
  5. * @author The Midgard Project, http://www.midgard-project.org
  6. * @version $Id: datamanager.php,v 1.23.2.4 2005/11/04 09:05:15 bergius Exp $
  7. * @copyright The Midgard Project, http://www.midgard-project.org
  8. * @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License
  9. */
  10.  
  11. /**
  12. * The main purpose of the Datamanager is to store arbitary data in an
  13. * arbitary Midgard object.
  14. *
  15. * The process of data storage and retrieval is completely automated and
  16. * controlled by the layout definition used for the object in question.
  17. *
  18. * It also provides a full form builder infrastructure which completely automates
  19. * both form handling and data output generation.
  20. *
  21. * <b>Layout database definition:</b>
  22. *
  23. * The following schema description uses a more-or-less BNF compatible syntax to
  24. * describe the structure of the layout schema Array.
  25. *
  26. * A layout database is a collection of layout definitions. The first layout will
  27. * be used as a default if the object in question has no layout specified. This is
  28. * the data structure that gets loaded by the Data Manager upon object creation.
  29. * The key for this array is used for indexing
  30. *
  31. * <pre>
  32. * &lt;layout database&gt; :== Array (
  33. * &lt;layout line&gt;
  34. * [ , &lt;layout line&gt; ... ]
  35. * );
  36. * &lt;layout line&gt; ::= &lt;layout name&gt; =&gt; &lt;layout definition&gt;,
  37. * &lt;layout name&gt; ::= &lt;string&gt;
  38. * &lt;string&gt; ::= Any PHP String
  39. * </pre>
  40. *
  41. * Each layout again consists of a descriptive string and the list of data
  42. * fields indexed by their name.
  43. *
  44. * <pre>
  45. * &lt;layout defintion&gt; ::= Array (
  46. * "description" =&gt; &lt;string&gt;
  47. * [, "locktimeout" =&gt; &lt;integer&gt; ]
  48. * [, "lockoverride" =&gt; "all" | "poweruser" | "admin" ]
  49. * [, "l10n_db" =&gt; &lt;string&gt; ]
  50. * [, "save_text" =&gt; &lt;string&gt; ]
  51. * [, "cancel_text" =&gt; &lt;string&gt; ]
  52. * , "fields" =&gt; &lt;field list&gt;
  53. * )
  54. *
  55. * &lt;field list&gt; ::= Array ( &lt;field name&gt; =&gt; &lt;field definition&gt;
  56. * [ , &lt;field name&gt; =&gt; &lt;field definition&gt; ... ] )
  57. *
  58. * &lt;field name&gt; ::= [a-zA-Z0-9]*
  59. * </pre>
  60. *
  61. * The locktimeout directive will override the global article lock timeout of
  62. * 60 minutes and sets it to the specified amount in minutes. The lockoverride
  63. * in turn will specify who will be able to override an existing lock; all means
  64. * all users, powerusers includes only powerusers and admins, while admin will
  65. * restrict it to sg admins only. If you set the lock timeout to 0, you will
  66. * disable the locking system.
  67. *
  68. * The field definition is the core of the magic. Here you define the behaviour
  69. * of each field you want to store. "name" is used as an array index for the data
  70. * retrieval array, "description" is used in the generator logic as field name.
  71. * The datatype specifies the name of the object that manages the data. Optional
  72. * fields include the name of the widget used in the data/form generation logic.
  73. * The optional field "location" specifies an explicit requirement where to save
  74. * the field. The data manager is currently unable to verify this so make sure
  75. * that the destination you specify here can take the data of the datatype you
  76. * want to store. See the docs of the individual datatypes for further reference.
  77. *
  78. * The object names given for datatype will be prefixed with "midcom_helper_
  79. * datamanager_datatype_", while the widget object names use "midcom_helper_
  80. * datamanager_widget_" as prefix. If you want custom datatypes or widgets not
  81. * given by Midcom, prefix them with "custom_", i.e. "midcom_helper_datamanager_
  82. * datatype_custom_mydatatype".
  83. *
  84. * If the value l10n_db is set, it overrides the default l10n database, possible
  85. * values are all valid component names, as the default component l10n DB is always
  86. * used (see below for details). Due to the current schema specification, it is
  87. * neccessary to specify this on a per-schema level. Per-schema-db configuration is
  88. * not supported at this time.
  89. *
  90. * The save_text and cancel_text values will be used as labels for the save and cancel
  91. * buttons in the datamanger. They are translated using the rules outlined above.
  92. *
  93. * <pre>
  94. * &lt;field definition&gt; :== Array (
  95. * "description" =&gt; &lt;string&gt;,
  96. * "datatype" =&gt; &lt;object identifier&gt;
  97. * [ , "widget" =&gt; &lt;object identifier&gt; ]
  98. * [ , "location" =&gt; &lt;storage name&gt; ]
  99. * [ , "hidden" =&gt; &lt;boolean&gt; ]
  100. * [ , "aisonly" =&gt; &lt;boolean&gt; ]
  101. * [ , "readonly" =&gt; &lt;boolean&gt; ]
  102. * [ , "default" =&gt; &lt;field value&gt; ]
  103. * [ , "required" =&gt; &lt;boolean&gt; ]
  104. * [ , "start_fieldgroup" =&gt; &lt;fieldgroup definition&gt; ]
  105. * [ , "end_fieldgroup" =&gt; "" ]
  106. * [ , "config_domain" =&gt; &lt;string&gt; ]
  107. * [ , "config_key" =&gt; &lt;string&gt; ]
  108. * [ , "helptext" =&gt; &lt;string&gt; ]
  109. * [ , &lt;option name&gt; =&gt; &lt;option value&gt; ... ]
  110. * [ , "validation" =&gt; &lt;fieldgroup definition&gt; ]
  111. * )
  112. *
  113. * &lt;object identifier&gt; ::= Any valid PHP class name in the namespace of the
  114. * Datamanger. (See above-)
  115. * &lt;storage name&gt; ::= 'parameter' | 'config' | 'attachment'
  116. * | &lt;storage object member name&gt;
  117. * &lt;storage object field name&gt; ::= Any valid member of the storage object.
  118. * &lt;option name&gt; ::= &lt;string&gt;
  119. * &lt;option value&gt; ::= Any valid PHP Datatype
  120. * &lt;field value&gt; ::= A value compatible to the datatype's value type
  121. * &lt;boolean&gt; ::= true|false
  122. * &lt;fieldgroup definition&gt; ::= Array (
  123. * "title" =&gt; &lt;string&gt;
  124. * [ , "css_group" =&gt; &lt;string&gt; ]
  125. * [ , "css_title" =&gt; &lt;string&gt; ]
  126. * )
  127. * </pre>
  128. *
  129. * Note, that widget and location all have their defaults corresponding to the
  130. * datatype you use. Also note, that some datatypes (for example the blob
  131. * datatypes) do not allow you a choice of where to store your data.
  132. *
  133. * Note also, that the Datamanger adds another entry into this array internally:
  134. *
  135. * <pre>
  136. * "name" =&gt; &lt;string&gt;
  137. * </pre>
  138. *
  139. * This is essentially the name of the field, which would not be available if you
  140. * only have the field definition available, as for example the Datatypes or
  141. * Widgets do.
  142. *
  143. * The special fields hidden and readonly affect the bevahoir of the form and view
  144. * generators. Hidden fields are ignored completly, nothing will be displayed
  145. * either in view- or in form-mode. Readonly fields are displayed in both views,
  146. * but instead of drawing the widget in form-mode, the datamanger draws the
  147. * regular view there. Both fields default to FALSE.
  148. *
  149. * The field aisonly is a special version of hidden, hiding the respective field
  150. * only in display_(view|form) calls outside of the AIS content admin. This too
  151. * defaults to FALSE.
  152. *
  153. * The default field is an indication what value should be used, if the field
  154. * in question is empty. It will automatically be automatically inserted by all
  155. * datatypes supporting default values upon extracting the fields from the
  156. * database.
  157. *
  158. * Setting the required flag on a field enforces an is_empty check before allowing
  159. * the user to save the object in question. The is_empty method is implemented on
  160. * a per-datatype basis, so you might want to check the specific datatypes in
  161. * what extent and with what meaning this operation is supported there.
  162. *
  163. * If the start_fieldgroup array is definied, it will start a new optical field
  164. * group before the currently defined field. The grouping is done through &lt;div&gt;
  165. * tags. The Title is printed, again enclosed by a &lt;div&gt; at the top of the
  166. * group. The optional css tags will be assigned to the opening div tags if
  167. * present. Each opened field group has to be closed using an end_fieldgroup
  168. * tag which will close the corresponding div tag. Note, that the schema writer
  169. * has to ensure that the fieldgroups are correctly paired, there is no checking
  170. * algorithm whatsoever which ensures the validity of the HTML to-be-generated.
  171. * It is possible, to have both a start and an end fieldgroup tag within the same
  172. * field, which will yield a group enclosing a single field. Note, that the hidden
  173. * tag has precedence over the grouping algorithm. A field which is invisible
  174. * will not start or end a field group.
  175. *
  176. * The two options "config_domain" and "config_key" are both required for the
  177. * config storage method, which is in essence a way of setting any arbitary
  178. * parameter, where config_domain is the parameter domain in question, and
  179. * config_key the parameter name. Apart from the extended configuration scheme,
  180. * this mode is otherwise identical to the storage method "parameter".
  181. *
  182. * The helptext parameter is there to allow for custom notes to the field.
  183. * Currently, the content of this field will be added as a tooltip to the field
  184. * in question. No HTML code is allowed in there yet.
  185. *
  186. * <b>Validation support:</b>
  187. *
  188. * The PEAR package HTML_Quickform must be installed to support validation.
  189. *
  190. * Validation is a new feature in MidCom 1.4.0. The implementation is based on
  191. * the Pear package HTML_Quickform so this must be installed for the
  192. * validationcode to work. If HTML_Quickform is not installed the field will
  193. * just not be validated - MidCom will just save it.
  194. *
  195. * A larger manual on HTML_Quickform is found here:
  196. * http://pear.php.net/manual/en/package.html.html-quickform.intro-validation.php
  197. *
  198. * To add validation to a field, you add a validation keyword to the schema
  199. * like this:
  200. *
  201. * <pre>
  202. * "validation" =&gt; array (
  203. * '&lt;type&gt;' =&gt; array (
  204. * 'message' =&gt; 'Some message to the user' ,
  205. * ['format' =&gt; 'string' , ]
  206. * ['function' =&gt; 'functionname'
  207. * [ 'object' =&gt; 'classname',] ]
  208. * )
  209. * )
  210. * </pre>
  211. *
  212. * As you see, the variables follow HTML_Quickform quite closely.
  213. *
  214. * You may also write your own validationfunctions by setting the function
  215. * parameter. If you function is part of a class you also have to set the
  216. * class-parameter.
  217. *
  218. * <b>Localizaion support:</b>
  219. *
  220. * The description and helptext of each field and all
  221. * fieldgroup titles are automatically localized using the l10db of either the current
  222. * component or the component referenced by the l10n_db schema configuration key.
  223. *
  224. * If the string in
  225. * question does not exist in either the current or the default language, it will
  226. * fall back to the midcom core l10n db searching there.
  227. *
  228. * For backwards
  229. * compatibility with the existing l10n databases and schemas, all name strings are converted
  230. * to lower-case before being looked-up in the l10n databases.
  231. *
  232. * <b>Automatic Cache invalidation:</b>
  233. *
  234. * The Datamanager will automatically invalidate the cache during editing of an
  235. * existing object. When in creation mode, it will invalidate the currently active
  236. * node as well (for the current context of course). Of course, if you don't use
  237. * the creation mode, you have to invalidate the right topic yourself.
  238. *
  239. * <b>Object destruction:</b>
  240. *
  241. * Due to the complex nature of the Datamanger's object hierarchy, PHP cannot
  242. * reliably garbage collect Datamanager instances (it fails to resolve the cyclic
  243. * references between the datamanager class, its datatypes and the widgets). Therefore
  244. * you have to call the destroy method every time you do no longer need a datamanger
  245. * instance. Only then you can safely let a datamanager reference out of scope.
  246. * It will destroy all datatypes and widgets and clears all internal references.
  247. *
  248. * This is especially important in long running requests like reindexing or
  249. * bulk uploads.
  250. *
  251. *
  252. * <b>Copyright references:</b>
  253. *
  254. * HTMLAREA, copyright (c) 2002-2004,
  255. * interactivetools.com, inc.
  256. * HTMLAREA is available under a BSD-derived license. More information
  257. * at http://www.interactivetools.com/products/htmlarea/license.html
  258. *
  259. * The DHTML Calendar, version 0.9.6 "Keep cool but don't freeze"
  260. * Copyright Mihai Bazon, 2002, 2003 | http://dynarch.com/mishoo/
  261. *
  262. * Details and latest version at:
  263. * http://dynarch.com/mishoo/calendar.epl
  264. *
  265. * This script is distributed under the GNU Lesser General Public License.
  266. * Read the entire license text here: http://www.gnu.org/licenses/lgpl.html
  267. *
  268. * @package midcom.helper.datamanager
  269. */
  270.  
  271. class midcom_helper_datamanager {
  272. /**
  273. * This MidgardObject is used for storing and retrieving the data. Any object
  274. * that is derived from them can also be used. Note that this member is populated
  275. * with a reference!
  276. *
  277. * @var MidgardObject
  278. * @access private
  279. */
  280. var $_storage;
  281. /**
  282. * This is the complete Layout database with which the system has been
  283. * initialized.
  284. *
  285. * @var Array
  286. * @access private
  287. */
  288. var $_layoutdb;
  289. /**
  290. * The layout currently in use, this is a reference into $_layoutdb.
  291. *
  292. * @var Array
  293. * @access private
  294. */
  295. var $_layout;
  296. /**
  297. * The index name of the layout currently in use.
  298. *
  299. * @var string
  300. * @access private
  301. */
  302. var $_layoutname;
  303. /**
  304. * The list of fields currently in use, this is a reference into $_layoutdb.
  305. *
  306. * @var Array
  307. * @access private
  308. */
  309. var $_fields;
  310. /**
  311. * The collection of datatypes corresponding to the fields out of the schema
  312. * file.
  313. *
  314. * @var Array
  315. * @access private
  316. */
  317. var $_datatypes;
  318. /**
  319. * This one holds the status of the process_form run. It is neccessary to avoid
  320. * multiple invocations of this method, like it is sometimes done by not ideally
  321. * designed components. It is null if process_form wasn't called yet.
  322. *
  323. * @var int
  324. * @access private
  325. */
  326. var $_processing_result;
  327. /**
  328. * Creation mode callback object reference
  329. *
  330. * @var object
  331. * @access private
  332. */
  333. var $_creation_code_objref;
  334. /**
  335. * Creation mode callback method name
  336. *
  337. * @var string
  338. * @access private
  339. */
  340. var $_creation_code_objmethod;
  341. /**
  342. * Creation mode schema name
  343. *
  344. * @var string
  345. * @access private
  346. */
  347. var $_creation_schema;
  348. /**
  349. * Creation mode flag
  350. *
  351. * @var bool
  352. * @access private
  353. */
  354. var $_creation;
  355. /**
  356. * A simple collection of field names from the required fields check. It is used
  357. * for switching required fields to a seperate css class.
  358. *
  359. * @var Array
  360. * @access private
  361. */
  362. var $_missing_required_fields;
  363. /**
  364. * The URL of the help icon. This URL is complete, no prefixes need to be added.
  365. *
  366. * @var string
  367. * @access private
  368. */
  369. var $_url_help_icon;
  370. /**
  371. * The URL of the lock icon. This URL is complete, no prefixes need to be added.
  372. *
  373. * @var string
  374. * @access private
  375. */
  376. var $_url_lock_icon;
  377. /**
  378. * This one will contain the lock data if the current storage object is locked.
  379. * It is set either by a previous call of check_log or by set_log. It is null
  380. * if it is undefined, false if there is no lock or an array containing the lock
  381. * of another user otherwise.
  382. *
  383. * @var Array
  384. * @access private
  385. */
  386. var $_lock;
  387. /**
  388. * $_ourlock will be true if and only if we are the
  389. * owner of the current lock; this variable is only valid if $_lock is an array.
  390. *
  391. * @var bool
  392. * @access private
  393. */
  394. var $_ourlock;
  395. /**
  396. * Pointer to a RuleRegistry singeltonobject.
  397. *
  398. * @var ???
  399. * @todo tarjei: Complete documentation
  400. * @access private
  401. */
  402. var $_rule_registry;
  403.  
  404. /**
  405. * This array always holds a current snapshot of the data. Changes to this array
  406. * are not propagated into the object.
  407. *
  408. * Besides the values of all fields, the following keys are added to the array as well:
  409. *
  410. * - _schema contains the name of the data schema in use.
  411. * - _storage_type contains the name of the table in which we are stored (WARNING, this value will be deprecated
  412. * during the DBA updates)
  413. * - _storage_id and _storage_guid hold the ID and GUID respecitvly of the storage object.
  414. *
  415. * @var Array
  416. */
  417. var $data;
  418. /**
  419. * Form field name prefix
  420. *
  421. * @var string
  422. */
  423. var $form_prefix;
  424. /**
  425. * Form URL prefix
  426. *
  427. * @var string
  428. */
  429. var $url_prefix;
  430. /**
  431. * The error string of the last call executed by the datamanager. The content of
  432. * this string is automatically appended to the content manager's processing
  433. * message and therefore needs only to be printed while in a non-AIS environment.
  434. * Note, that this string is HTML-capable, it should be enclosed in a <div> or
  435. * <p> upon printing, as those tags are not allowed in here.
  436. *
  437. * @var string
  438. */
  439. var $errstr;
  440. /**
  441. * URL prefix to the form
  442. *
  443. * @var string
  444. */
  445. var $url_me;
  446. /**
  447. * Datamanager L10n Database
  448. *
  449. * @access private
  450. * @var midcom_services__i18n_l10n
  451. */
  452. var $_l10n;
  453. /**
  454. * MidCOM L10n Database
  455. *
  456. * @access private
  457. * @var midcom_services__i18n_l10n
  458. */
  459. var $_l10n_midcom;
  460.  
  461. /**
  462. * The primary L10n DB to use for schema translation.
  463. *
  464. * @var midcom_services__i18n_l10n
  465. * @access private
  466. */
  467. var $_l10n_schema = null;
  468. /* *************************** */
  469. /* ** Object Initialization ** */
  470. /**
  471. * The constructor loads the layout database, verifies its structure and
  472. * initializes the complete class for usage. No object gets loaded at this
  473. * point.
  474. *
  475. * The path to the schema database can be anything accepted by
  476. * midcom_get_snippet_content().
  477. *
  478. * @param mixed $layoutdb Either a string with the URL to a layoutDB or an Array containing the DB.
  479. * @see midcom_get_snippet_content()
  480. */
  481. function midcom_helper_datamanager ($layoutdb = null)
  482. {
  483. global $midcom;
  484. global $midcom_errstr;
  485.  
  486. debug_push_class(__CLASS__, __FUNCTION__);
  487.  
  488. if (is_null($layoutdb))
  489. {
  490. $this = false;
  491. $midcom_errstr = "Default Constructor not allowed";
  492. debug_add($midcom_errstr);
  493. debug_pop();
  494. return false;
  495. }
  496.  
  497. $midgard = $midcom->get_midgard();
  498.  
  499. $this->form_prefix = "midcom_helper_datamanager_";
  500. $this->url_prefix = $midcom->get_context_data(MIDCOM_CONTEXT_ANCHORPREFIX);
  501. $this->url_me = $midgard->uri;
  502. if (array_key_exists('QUERY_STRING',$_SERVER)
  503. && strlen(trim($_SERVER['QUERY_STRING'])) > 0 )
  504. {
  505. // We have HTTP GET parameters present, save them through the request.
  506. $this->url_me .= '?' . $_SERVER['QUERY_STRING'];
  507. }
  508.  
  509. $this->_storage = null;
  510. $this->_layoutdb = null;
  511. $this->_layout = null;
  512. $this->_layoutname = "";
  513. $this->_fields = null;
  514. $this->_datatypes = null;
  515. $this->_processing_result = null;
  516. $this->_creation_code_objref = null;
  517. $this->_creation_code_objmethod = null;
  518. $this->_creation_schema = null;
  519. $this->_creation = false;
  520. $this->_missing_required_fields = Array();
  521. $this->errstr = "";
  522. $this->data = null;
  523. $this->_url_help_icon = MIDCOM_STATIC_URL . '/stock-icons/16x16/stock_help-agent.png';
  524. $this->_url_lock_icon = MIDCOM_STATIC_URL . '/stock-icons/24x24/lock.png';
  525. $this->_lock = null;
  526. $this->_ourlock = null;
  527. $i18n =& $GLOBALS["midcom"]->get_service("i18n");
  528. $this->_l10n = $i18n->get_l10n("midcom.helper.datamanager");
  529. $this->_l10n_midcom = $i18n->get_l10n("midcom");
  530.  
  531. $this->_load_schema_database($layoutdb);
  532. debug_pop ();
  533. }
  534. /**
  535. * Initializes the datamanager for object creation.
  536. *
  537. * In the creation mode, special rules apply. First, there must be a callback from
  538. * the application itself, that is executed when the dm need to create the true
  539. * storage object (after the user first clicks save, that is). The function must
  540. * return an array: The parameter "strorage" is mandatory and holds a reference(!)
  541. * to the storage object to be used. Note, that this object is passed by reference
  542. * to the complete datamanager system, so that all changes propagate accordingly.
  543. * The parameter "success" is optional, setting it to false tells the datamanager
  544. * to stay in the edit loop rather then complete it. Note, that this function must
  545. * create an empty object without any references to schema names and so on.
  546. *
  547. * The callback function receives only one parameter, which is a reference (!!)
  548. * to the datamanager object itself.
  549. *
  550. * Note, that the callback should absolutly try to create an empty record somehow,
  551. * telling success=false on all minor errors along with an appropriate error
  552. * message through the append_error method of the datamanager. If no storage
  553. * object can be created, NULL should be returned instead with an appropriate
  554. * error message through append_error. Know, that it is not possible, to retain
  555. * the user's input in the form in that case!
  556. *
  557. * The datamanager internally keeps track of the schema to be used for the new
  558. * record. The parameter $schema therefor is only relevant on the first call of
  559. * the function. Its value is tracked through a hidden variable within the input
  560. * form to save the application from keeping track of this variable over the
  561. * requests.
  562. *
  563. * @param string $schema The schema name which should be used for creation of the new object.
  564. * @param object $object The callback object containing the creation code.
  565. * @param string $callback The method name that should be used to create the new object.
  566. * @return bool Indicating success
  567. */
  568. function init_creation_mode ($schema, &$object, $callback = "_dm_create_callback") {
  569. $this->_creation_code_objref =& $object;
  570.  
  571.  
  572. $this->_creation_code_objmethod = $callback;
  573. if (array_key_exists("midcom_helper_datamanager_creation_schema", $_REQUEST))
  574. $this->_creation_schema = $_REQUEST["midcom_helper_datamanager_creation_schema"];
  575. else
  576. $this->_creation_schema = $schema;
  577. $this->_creation = true;
  578. $this->_storage = null;
  579. return $this->_true_init(null);
  580. }
  581. /**
  582. * This method is responsible for the initialization of the datamanager to a
  583. * given object.
  584. *
  585. * The datamanager loads the object and
  586. * initializes all local fields accordingly. All datatypes get instantinated
  587. * and the data array gets populated. If the object has no schema accociated with
  588. * it, it defaults to the first layout in the database.
  589. *
  590. * @param MidgardObject $storage The storage object to which the DM should be linked to.
  591. * @param string $schema Do not autodetect the schema but use the one given here.
  592. * This is useful if you want to edit the same object with more then one schema.
  593. * Can be omitted.
  594. * @return bool True on success, false on failure, errors go to the debug log.
  595. */
  596. function init (&$storage, $schema = null) {
  597. $this->_storage =& $storage;
  598. return $this->_true_init($schema);
  599. }
  600. /**
  601. * This is the common initialization work shared between the existing-object
  602. * and the new-object ("creation mode") init procedure.
  603. *
  604. * It will translate all descriptions and helptexts automatically.
  605. *
  606. * Note, that the string is translated to <i>lower case</i> before
  607. * translation, as this is the usual form how strings are in the
  608. * l10n database. (This is for backwards compatibility mainly.)
  609. *
  610. * @param string $schema Do not autodetect the schema but use the one given here.
  611. * This is useful if you want to edit the same object with more then one schema.
  612. * @return bool Indicating success
  613. * @access private
  614. */
  615. function _true_init ($schema) {
  616. debug_push_class(__CLASS__, __FUNCTION__);
  617. $this->errstr = "";
  618. if ( ! is_object($this->_storage)
  619. && ! $this->_creation
  620. )
  621. {
  622. debug_add ("No object given!", MIDCOM_LOG_ERROR);
  623. debug_pop ();
  624. return false;
  625. }
  626. // get the layout of article, use the first defined layout if
  627. // none specified
  628. if ($this->_creation)
  629. {
  630. $this->_layoutname = $this->_creation_schema;
  631. }
  632. else if (is_null($schema))
  633. {
  634. $this->_layoutname = $this->_storage->parameter ("midcom.helper.datamanager", "layout");
  635. if (! $this->_layoutname)
  636. {
  637. $layouts = array_keys ($this->_layoutdb);
  638. $this->_layoutname = $layouts[0];
  639. debug_add ("Object has no schema, trying to use default: {$this->_layoutname}", MIDCOM_LOG_INFO);
  640. }
  641. }
  642. else
  643. {
  644. $this->_layoutname = $schema;
  645. }
  646. debug_add("Got Layout $this->_layoutname. Validating it...");
  647. if (array_key_exists($this->_layoutname, $this->_layoutdb))
  648. {
  649. debug_add("Layout $this->_layoutname found.");
  650. $this->_layout =& $this->_layoutdb[$this->_layoutname];
  651. $this->_fields =& $this->_layout["fields"];
  652. }
  653. else
  654. {
  655. $GLOBALS["midcom_errstr"] = "Layout does not exist!";
  656. debug_add ($GLOBALS["midcom_errstr"], <a href="../undocumented/_lib_constants_php.html#defineMIDCOM_LOG_ERROR">MIDCOM_LOG_ERROR</a>);
  657. debug_pop ();
  658. return false;
  659. }
  660.  
  661. if (array_key_exists('l10n_db', $this->_layout))
  662. {
  663. $comp = $this->_layout['l10n_db'];
  664. }
  665. else
  666. {
  667. $comp = $GLOBALS['midcom']->get_context_data(<a href="../undocumented/_lib_constants_php.html#defineMIDCOM_CONTEXT_COMPONENT">MIDCOM_CONTEXT_COMPONENT</a>);
  668. }
  669. debug_add("We have to translate the schema using the database {$comp}.");
  670. $i18n =& $GLOBALS['midcom']->get_service('i18n');
  671. $this->_l10n_schema = $i18n->get_l10n($comp);
  672. $this->_translate_schema_field($this->_layout['description']);
  673. // Complete Field Defaults
  674. if (! array_key_exists("locktimeout", $this->_layout))
  675. {
  676. $this->_layout["locktimeout"] = 60;
  677. }
  678. if (! array_key_exists("lockoverride", $this->_layout))
  679. {
  680. $this->_layout["lockoverride"] = "poweruser";
  681. }
  682. if (! array_key_exists('save_text', $this->_layout))
  683. {
  684. $this->_layout['save_text'] = 'save';
  685. }
  686. if (! array_key_exists('cancel_text', $this->_layout))
  687. {
  688. $this->_layout['cancel_text'] = 'cancel';
  689. }
  690.  
  691. $this->_translate_schema_field($this->_layout['save_text']);
  692. $this->_translate_schema_field($this->_layout['cancel_text']);
  693.  
  694. foreach ($this->_fields as $name => $field)
  695. {
  696. $this->_fields[$name]["name"] = $name;
  697. if (!array_key_exists("helptext",$field))
  698. {
  699. $this->_fields[$name]["helptext"] = "";
  700. }
  701. if (!array_key_exists("hidden",$field))
  702. {
  703. $this->_fields[$name]["hidden"] = false;
  704. }
  705. if (!array_key_exists("readonly",$field))
  706. {
  707. $this->_fields[$name]["readonly"] = false;
  708. }
  709. if (!array_key_exists("required",$field))
  710. {
  711. $this->_fields[$name]["required"] = false;
  712. }
  713.  
  714. if (!array_key_exists("aisonly",$field))
  715. {
  716. $this->_fields[$name]["aisonly"] = false;
  717. }
  718. // Translate the field
  719. $this->_translate_schema_field($this->_fields[$name]['description']);
  720. $this->_translate_schema_field($this->_fields[$name]['helptext']);
  721. if (array_key_exists('start_fieldgroup', $field))
  722. {
  723. $this->_translate_schema_field($this->_fields[$name]['start_fieldgroup']['title']);
  724. }
  725. if ( array_key_exists("location", $field)
  726. && $field["location"] == "config"
  727. && ( ! array_key_exists("config_domain", $field)
  728. || ! array_key_exists("config_key", $field)))
  729. {
  730. $GLOBALS["midcom_errstr"] = "Config field detected without config_domain or config_key";
  731. debug_add ($GLOBALS["midcom_errstr"], <a href="../undocumented/_lib_constants_php.html#defineMIDCOM_LOG_ERROR">MIDCOM_LOG_ERROR</a>);
  732. debug_print_r ("Field $name was defined as: ", $field);
  733. debug_pop();
  734. return false;
  735. }
  736. }
  737. // If we have a datatype listing, we kill them before creating the new one
  738. // This covers the cases where we re-init the datamanager.
  739. if (! is_null($this->_datatypes))
  740. {
  741. $this->_destroy_types();
  742. }
  743. // Instantinate all Datatype Concepts
  744. $this->_datatypes = Array();
  745. foreach ($this->_fields as $name => $field)
  746. {
  747. debug_print_r("Processing $name:", $field);
  748. $classname = "midcom_helper_datamanager_datatype_" . $field["datatype"];
  749. $this->_datatypes[$name] =& new $classname ($this, $this->_storage, $field);
  750. if (! $this->_datatypes[$name])
  751. {
  752. $GLOBALS["midcom_errstr"] = "Could not instantinate " . $name . " Datatype Class.";
  753. debug_add($GLOBALS["midcom_errstr"], <a href="../undocumented/_lib_constants_php.html#defineMIDCOM_LOG_ERROR">MIDCOM_LOG_ERROR</a>);
  754. debug_pop();
  755. return false;
  756. }
  757. }
  758. $this->_populate_data();
  759. debug_pop();
  760. return true;
  761. }
  762.  
  763. /*********************************/
  764. /*** Form Processing Functions ***/
  765. /**
  766. * This method does all processing related to datamanager-generated forms. You
  767. * must call this method during your handle phase and act according to the
  768. * constant returned:
  769. *
  770. * - <b>MIDCOM_DATAMGR_FAILED:</b> Something critical occured, processing failed.
  771. * - <b>MIDCOM_DATAMGR_CANCELLED:</b> Editing has been cancelled by the user, you
  772. * should return to view-mode, no changes made. In case of a creation loop,
  773. * the actual record has already been created and must be deleted by the
  774. * callee manually.
  775. * - <b>MIDCOM_DATAMGR_SAVED:</b> Data has been save, you should return to
  776. * view-mode.
  777. * - <b>MIDCOM_DATAMGR_EDITING:</b> We are still editing the data, keep calling the
  778. * form-mode. If we are in creation mode, this means that object creation
  779. * happened, but there was some validation error or the such, consult the
  780. * datamanager's error messages for further details; an object has been
  781. * created.
  782. * - <b>MIDCOM_DATAMGR_CREATEFAILED:</b> The creation callback could not create an
  783. * empty record for use with the datamanager. This is serious. No new
  784. * record has been created yet.
  785. * - <b>MIDCOM_DATAMGR_CREATING:</b> This is a variant of EDITING, the callee should show
  786. * the edit form now. It is the first time, the edit interface is shown, no
  787. * data has been stored yet.
  788. * - <b>MIDCOM_DATAMGR_CANCELLED_NONECREATED:</b> The user aborted the creation of an new
  789. * object before any new object could have been created. The application
  790. * should revert to some welcome screen, nothing has to be deleted.
  791. *
  792. * This method does its work only once. Consecutive calls will only yield the
  793. * same result as the first call to avoid trouble with multiple updated runs
  794. * in the datatypes.
  795. *
  796. * It will also call the _update_nemein_rcs helper to utilize its RCS mechanism
  797. * if available on any successful storage to