root/trunk/midcom/midcom.helper.datamanager2/schema.php

Revision 17556, 19.8 kB (checked in by flack, 3 weeks ago)

yet more PHP5-style constructors

  • Property svn:keywords set to Author Date Id Revision
Line 
1 <?php
2 /**
3  * @package midcom.helper.datamanager2
4  * @author The Midgard Project, http://www.midgard-project.org
5  * @version $Id$
6  * @copyright The Midgard Project, http://www.midgard-project.org
7  * @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License
8  */
9
10 /**
11  * Datamanager 2 Schema class.
12  *
13  * This class encapsulates Datamanager Schemas. It contains all information required to construct
14  * the types and widgets of a given data schema. The base class constructs out of a Datamanager 2
15  * Schema definition, which is not compatible with a legacy Datamanager 1 Schema, you need to
16  * use the appropriate subclass to handle them dynamically.
17  *
18  * <b>Schema Definition</b>
19  *
20  * See {@link http://www.midgard-project.org/documentation/midcom-2-5-datamanager-rewrite-schema-definition/}
21  * for now.
22  *
23  * <b>Storage</b>
24  * When using the Midgard storage backend, it is possible to define a callback class to be called
25  * that will then save the object. The class is defined as follows. Please note that if the classname
26  * follows the midcom hierarchy, it may be loaded automatically.
27  *
28  * The class must satisfy the following interfaces:
29  * <code>
30  * class midcom_admin_parameters_callback {
31  *      // params:
32  *      // name: the name of the field
33  *      // data: the data that comes from the type defined.
34  *      // storage: a reference to the datamanager's storageclass.
35  *      function on_load_data($name,&$storage);
36  *      function on_store_data($name, $data,&$storage);
37  * }
38  * </code>
39  *
40  * What the functions should return depends on the datatype they return to.
41  *
42  * The callback may be defined in the schema like this:
43  * <code>
44  * 'fields' => Array
45  * (
46  *      'parameters' => Array
47  *       (
48  *           'title' => 'url name',
49  *           'storage' => Array
50  *            (
51  *                   'location' => 'object',
52  *                   'callback' => 'midcom_admin_parameters_callbacks_storage',
53  *            ),
54  *            'type' => ..,
55  *            'widget' => ..
56  *       ),
57  * </code>
58  *
59  * <b>Important</b>
60  * It is only possible to define one storage callback per schema! If you want more than one,
61  * encapsulate this in your class.
62  *
63  * @todo Complete documentation
64  * @package midcom.helper.datamanager2
65  */
66 class midcom_helper_datamanager2_schema extends midcom_baseclasses_components_purecode
67 {
68     /**
69      * The general field listing, indexed by their name. It contains the full field record
70      * which has been completed with all defaults.
71      *
72      * You may changes settings outlined here, be aware though, that types and/or widgets
73      * spawned based on this schema do normally not reference these configuration block
74      * directly, but instead they usually merge the settings made into their own internal
75      * default config. You can still adjust the types, which usually have their settings
76      * available as public members though.
77      *
78      * @var Array
79      */
80     var $fields = Array();
81
82     /**
83      * The title of this schema, used to display schemas when
84      *
85      * @var string
86      */
87     var $description = '';
88
89     /**
90      * The name of the schema ("identifier").
91      *
92      * @var string
93      */
94     var $name = '';
95
96     /**
97      * The primary L10n DB to use for schema translation.
98      *
99      * @var midcom_services__i18n_l10n
100      */
101     var $l10n_schema = null;
102
103     /**
104      * The raw schema array as read by the system. This is a reference
105      * into the schema database.
106      *
107      * @access private
108      * @var Array
109      */
110     var $_raw_schema = null;
111
112     /**
113      * The raw schema database as read by the system.
114      *
115      * @access private
116      * @var Array
117      */
118     var $_raw_schemadb = null;
119
120     /**
121      * The schema database path as read by the system.
122      *
123      * @access private
124      * @var Array
125      */
126     var $_schemadb_path = null;
127
128     /**
129      * A simple array holding the fields in the order they should be rendered identified
130      * by their name.
131      *
132      * @var Array
133      */
134     var $field_order = Array();
135
136     /**
137      * The operations to add to the form.
138      *
139      * This is a simple array of commands, valid entries are 'save', 'cancel', 'next' and
140      * 'previous', 'edit' is forbidden, other values are not interpreted by the DM infrastructure.
141      *
142      * @var Array
143      */
144     var $operations = Array('save' => '', 'cancel' => '');
145
146     /**
147      * This array holds custom information attached to this schema. Its exact usage is component
148      * dependant.
149      *
150      * @var Array
151      */
152     var $customdata = Array();
153
154     /**
155      * Form-wide validation callbacks, executed by QuickForm. This is a list of arrays. Each
156      * array defines a single callback, along with a snippet or file location that should be
157      * auto-loaded in case the function is missing.
158      *
159      * @var Array
160      */
161     var $validation = Array();
162
163     /**
164      * Custom data filter rules.
165      *
166      * This is a list of arrays. Each array defines a single callback,
167      * a field list according to HTML_QuickForm::applyFilter() along with a snippet or file location
168      * that should be auto-loaded in case the function is missing.
169      *
170      * @var Array
171      */
172     var $filters = Array();
173
174     /**
175      * Construct a schema, takes a schema snippet URI resolvable through the
176      * midcom_get_snippet_content() helper function.
177      *
178      * @param mixed $schemadb Either the path or the already loaded schema database
179      *     to use.
180      * @param string $name The name of the Schema to use. It must be a member in the
181      *     specified schema database. If unspecified, the default schema is used.
182      * @see midcom_get_snippet_content()
183      */
184     function __construct($schemadb, $name = null, $schemadb_path = null)
185     {
186         $this->_component = 'midcom.helper.datamanager2';
187         parent::__construct();
188         $this->_schemadb_path = $schemadb_path;
189
190         $this->_load_schemadb($schemadb);
191
192         if ($name === null)
193         {
194             reset($this->_raw_schemadb);
195             $name = key($this->_raw_schemadb);
196         }
197
198         $this->_load_schema($name);
199     }
200
201     /**
202      * This function loads the schema database into the class, either from a copy
203      * already in memory, or from a URL resolvable by midcom_get_snippet_content.
204      *
205      * @param mixed $schemadb Either the path or the already loaded schema database
206      *     to use.
207      * @see midcom_get_snippet_content()
208      */
209     function _load_schemadb($schemadb)
210     {
211         if (is_string($schemadb))
212         {
213             $data = midcom_get_snippet_content($schemadb);
214             $result = eval ("\$this->_raw_schemadb = Array ( {$data}\n );");
215             if ($result === false)
216             {
217                 $_MIDCOM->generate_error(MIDCOM_ERRCRIT,
218                     "Failed to parse the schema definition in '{$schemadb}', see above for PHP errors.");
219                 // This will exit.
220             }
221         }
222         else if (is_array($schemadb))
223         {
224             $this->_raw_schemadb = $schemadb;
225         }
226         else
227         {
228             debug_push_class(__CLASS__, __FUNCTION__);
229             debug_print_r('Passed schema db was:', $schemadb);
230             debug_pop();
231             $_MIDCOM->generate_error(MIDCOM_ERRCRIT, 'Failed to access the schema database: Invalid variable type while constructing.');
232             // This will exit.
233         }
234     }
235
236     /**
237      * This function parses the schema and populates all members with the corresponding
238      * information, completing defaults where necessary.
239      *
240      * It will automatically translate all descriptive fields according to the rules
241      * outlined in the translate_schema_field() helper function.
242      *
243      * @param string $name The name of the schema to load.
244      */
245     function _load_schema($name)
246     {
247         // Setup the raw schema reference
248         if (! array_key_exists($name, $this->_raw_schemadb))
249         {
250             $_MIDCOM->generate_error(MIDCOM_ERRCRIT, "The schema {$name} was not found in the schema database.");
251             // This will exit.
252         }
253         $this->_raw_schema =& $this->_raw_schemadb[$name];
254
255         // Populate the l10n_schema member
256         if (array_key_exists('l10n_db', $this->_raw_schema))
257         {
258             $l10n_name = $this->_raw_schema['l10n_db'];
259         }
260         else
261         {
262             $l10n_name = $_MIDCOM->get_context_data(MIDCOM_CONTEXT_COMPONENT);
263         }
264         $this->_l10n_schema = $_MIDCOM->i18n->get_l10n($l10n_name);
265
266         if (array_key_exists('operations', $this->_raw_schema))
267         {
268             $this->operations = $this->_raw_schema['operations'];
269         }
270         if (array_key_exists('customdata', $this->_raw_schema))
271         {
272             $this->customdata = $this->_raw_schema['customdata'];
273         }
274         if (array_key_exists('validation', $this->_raw_schema))
275         {
276             $this->validation = $this->_raw_schema['validation'];
277         }
278         if (array_key_exists('filters', $this->_raw_schema))
279         {
280             $this->filters = $this->_raw_schema['filters'];
281         }
282
283         $this->description = $this->_raw_schema['description'];
284         $this->name = $name;
285
286         foreach ($this->_raw_schema['fields'] as $name => $data)
287         {
288             $data['name'] = $name;
289             $this->append_field($name, $data);
290         }
291
292         if (   $this->_config->get('include_metadata_required')
293             && $this->_schemadb_path
294             && $this->_schemadb_path != $GLOBALS['midcom_config']['metadata_schema'])
295         {
296             // Include required fields from metadata schema to the schema
297             $metadata_schema = midcom_helper_datamanager2_schema::load_database($GLOBALS['midcom_config']['metadata_schema']);
298             if (isset($metadata_schema['metadata']))
299             {
300                 $prepended = false;
301                 foreach ($metadata_schema['metadata']->fields as $name => $field)
302                 {
303                     if ($field['required'])
304                     {
305                         if (!$prepended)
306                         {
307                             $field['static_prepend'] = "<h3 style='clear: left;'>" . $_MIDCOM->i18n->get_string('metadata', 'midcom') . "</h3>\n" . $field['static_prepend'];
308                             $prepended = true;
309                         }
310                         $this->append_field($name, $field);
311                     }
312                 }
313             }
314         }
315     }
316
317     /**
318      * This function adds a new field to the schema, appending it at the end of the
319      * current field listing.
320      *
321      * This is callable after the construction of the object, to allow you to add
322      * additional fields like component required fields to the list.
323      *
324      * This can also be used to merge schemas together.
325      *
326      * It will complete the field's default and set the corresponding type and widget
327      * setups.
328      *
329      * @param string $name The name of the field to add
330      * @param Array $config The fields' full configuration set.
331      */
332     function append_field($name, $config)
333     {
334         if (array_key_exists($name, $this->fields))
335         {
336             $_MIDCOM->generate_error(MIDCOM_ERRCRIT, "Duplicate field {$name} encountered, schema operation is invalid. Aborting.");
337             // This will exit.
338         }
339
340         $this->field_order[] = $name;
341         $this->_complete_field_defaults($config);
342         $this->fields[$name] = $config;
343     }
344
345     /**
346      * Internal helper function which completes all missing field declaration members
347      * so that all fields can be treated uniformly.
348      *
349      * @todo Refactor in subfunctions for better readability.
350      */
351     function _complete_field_defaults(&$config)
352     {
353         // Sanity check for b0rken schemas, missing type/widget would cause DM & PHP to barf later on...
354         if (   !array_key_exists('type', $config)
355             || empty($config['type']))
356         {
357             $_MIDCOM->generate_error(MIDCOM_ERRCRIT, "Field '{$config['name']}' in schema '{$this->name}' loaded from {$this->_schemadb_path} is missing *type* definition");
358             // this will exit
359         }
360         if (   !array_key_exists('widget', $config)
361             || empty($config['widget']))
362         {
363             $_MIDCOM->generate_error(MIDCOM_ERRCRIT, "Field '{$config['name']}' in schema '{$this->name}' loaded from {$this->_schemadb_path} is missing *widget* definition");
364             // this will exit
365         }
366         /* Rest of the defaults */
367         // Simple ones
368         $simple_defaults = array
369         (
370             'description' => null,
371             'helptext' => null,
372             'static_prepend' => null,
373             'static_append' => null,
374             'read_privilege' => null,
375             'write_privilege' => null,
376             'default' => null,
377             'readonly' => false,
378             'hidden' => false,
379             'aisonly' => false,
380             'required' => false,
381         );
382         foreach ($simple_defaults as $property => $value)
383         {
384             if (! array_key_exists( $property, $config))
385             {
386                 $config[ $property] = $value;
387             }
388         }
389         unset($property, $value);
390
391         // And complex ones
392         if (! array_key_exists('storage', $config))
393         {
394             $config['storage'] = Array
395             (
396                 'location' => 'parameter',
397                 'domain' => 'midcom.helper.datamanager2'
398             );
399         }
400         else
401         {
402             if (is_string($config['storage']))
403             {
404                 $config['storage'] = Array ( 'location' => $config['storage'] );
405             }
406             if (strtolower($config['storage']['location']) === 'parameter')
407             {
408                 $config['storage']['location'] = strtolower($config['storage']['location']);
409                 if (! array_key_exists('domain', $config['storage']))
410                 {
411                     $config['storage']['domain'] = 'midcom.helper.datamanager2';
412                 }
413
414                 if (! array_key_exists('multilang', $config['storage']))
415                 {
416                     $config['storage']['multilang'] = false;
417                 }
418             }
419         }
420         if (! array_key_exists('index_method', $config))
421         {
422             $config['index_method'] = 'auto';
423         }
424         if (! array_key_exists('index_merge_with_content', $config))
425         {
426             $config['index_merge_with_content'] = true;
427         }
428
429         if (   ! array_key_exists('type_config', $config)
430             || ! is_array($config['type_config']))
431         {
432             $config['type_config'] = Array();
433         }
434         if (   ! array_key_exists('widget_config', $config)
435             || ! is_array($config['type_config']))
436         {
437             $config['widget_config'] = Array();
438         }
439         if (! array_key_exists('customdata', $config))
440         {
441             $config['customdata'] = Array();
442         }
443
444         if (   ! array_key_exists('validation', $config)
445             || ! $config['validation'])
446         {
447             $config['validation'] = Array();
448         }
449         else if (! is_array($config['validation']))
450         {
451             $config['validation'] = Array($config['validation']);
452         }
453         foreach ($config['validation'] as $key => $rule)
454         {
455             if (! is_array($rule))
456             {
457                 if ($rule['type'] == 'compare')
458                 {
459                     $_MIDCOM->generate_error(MIDCOM_ERRCRIT,
460                         "Missing compare_with option for compare type rule {$key} on field {$config['name']}, this is a required option.");
461                     // This will exit.
462                 }
463                 $config['validation'][$key] = Array
464                 (
465                     'type' => $rule,
466                     'message' => "validation failed: {$rule}",
467                     'format' => ''
468                 );
469             }
470             else
471             {
472                 if (! array_key_exists('type', $rule))
473                 {
474                     $_MIDCOM->generate_error(MIDCOM_ERRCRIT,
475                         "Missing validation rule type for rule {$key} on field {$config['name']}, this is a required option.");
476                     // This will exit.
477                 }
478                 if (! array_key_exists('message', $rule))
479                 {
480                     $config['validation'][$key]['message'] = "validation failed: {$rule['type']}";
481                 }
482                 if (! array_key_exists('format', $rule))
483                 {
484                     $config['validation'][$key]['format'] = '';
485                 }
486                 if ($rule['type'] == 'compare')
487                 {
488                     if (! array_key_exists('compare_with', $rule))
489                     {
490                         $_MIDCOM->generate_error(MIDCOM_ERRCRIT,
491                             "Missing compare_with option for compare type rule {$key} on field {$config['name']}, this is a required option.");
492                         // This will exit.
493                     }
494                 }
495             }
496         }
497     }
498
499     /**
500      * Schema translation helper, usable by components from the outside.
501      *
502      * The l10n db from the schema is used first, the Datamanager l10n db second and
503      * the MidCOM core l10n db last. If the string is not found in both databases,
504      * the string is returned unchanged.
505      *
506      * Note, that the string is translated to <i>lower case</i> before
507      * translation, as this is the usual form how strings are in the
508      * l10n database. (This is for backwards compatibility mainly.)
509      *
510      * @param string $string The string to be translated.
511      * @return string The translated string.
512      */
513     function translate_schema_string ($string)
514     {
515         $translate_string = strtolower($string);
516
517         if (   $this->_l10n_schema !== null
518             && $this->_l10n_schema->string_available($translate_string))
519         {
520             return $this->_l10n_schema->get($translate_string);
521         }
522         else if ($this->_l10n->string_available($translate_string))
523         {
524             return $this->_l10n->get($translate_string);
525         }
526         else if ($this->_l10n_midcom->string_available($translate_string))
527         {
528             return $this->_l10n_midcom->get($translate_string);
529         }
530
531         return $string;
532     }
533
534     /**
535      * Helper function which transforms a raw schema database (either already parsed or
536      * based on a URL to a schemadb) into a list of schema class instances.
537      *
538      * This function may (and usually will) be called statically.
539      *
540      * @param mixed $raw_db Either an already created raw schema array, or a midgard_get_snippet_content
541      *     compatible URL to a snippet / file from which the db should be loaded.
542      * @return Array An array of midcom_helper_datamanager2_schema class instances.
543      * @see midcom_get_snippet_content()
544      */
545     function load_database($raw_db)
546     {
547         $path = null;
548         if (is_string($raw_db))
549         {
550             $path = $raw_db;
551             $data = midcom_get_snippet_content($raw_db);
552             $result = eval ("\$raw_db = Array ( {$data}\n );");
553             if ($result === false)
554             {
555                 $_MIDCOM->generate_error(MIDCOM_ERRCRIT,
556                     "Failed to parse the schema database loaded from '{$raw_db}', see above for PHP errors.");
557                 // This will exit.
558             }
559         }
560
561         $schemadb = Array();
562
563         foreach ($raw_db as $name => $raw_schema)
564         {
565             $schemadb[$name] = new midcom_helper_datamanager2_schema($raw_db, $name, $path);
566         }
567         return $schemadb;
568     }
569
570     /**
571      * Registers a schema into the session so it is readable by the imagepopup.
572      * @return string the form sessionkey
573      * @throws none
574      * @access public
575      *
576      */
577      function register_to_session($guid)
578      {
579         $key = $this->name $guid;
580         // Seems we do not need this anymore, but return key still
581         return $key;
582
583         $session =& $_MIDCOM->get_service('session');
584         $session->set('midcom.helper.datamanager2', $key, $this->_raw_schema);
585         return $key;
586
587      }
588 }
589
590 ?>
Note: See TracBrowser for help on using the browser.