1 // ==========================================================================
  2 // Project:   The M-Project - Mobile HTML5 Application Framework
  3 // Copyright: (c) 2010 M-Way Solutions GmbH. All rights reserved.
  4 // Creator:   Sebastian
  5 // Date:      18.11.2010
  6 // License:   Dual licensed under the MIT or GPL Version 2 licenses.
  7 //            http://github.com/mwaylabs/The-M-Project/blob/master/MIT-LICENSE
  8 //            http://github.com/mwaylabs/The-M-Project/blob/master/GPL-LICENSE
  9 // ==========================================================================
 10 
 11 m_require('core/utility/logger.js');
 12 
 13 /**
 14  * @class
 15  *
 16  * M.ModelAttribute encapsulates all meta information about a model record's property:
 17  * * is it required?
 18  * * what data type is it of? (important for mapping to relational database schemas)
 19  * * what validators shall be applied
 20  * All M.ModelAttributes for a model record are saved under {@link M.Model#__meta} property of a model.
 21  * Each ModelAttribute is saved with the record properties name as key.
 22  * That means:
 23  *
 24  * model.record[propA] is the value of the property.
 25  * model.__meta[propA] is the {@link M.ModelAttribute} object for the record property.
 26  *
 27  * @extends M.Object
 28  */
 29 M.ModelAttribute = M.Object.extend(
 30 /** @scope M.ModelAttribute.prototype */ {
 31 
 32     /**
 33      * The type of this object.
 34      *
 35      * @type String
 36      */
 37     type: 'M.ModelAttribute',
 38 
 39     /**
 40      * The data type for the model record property.
 41      * Extremely important e.g. to map model to relational database table.
 42      *
 43      * @type String
 44      */
 45     dataType: null,
 46 
 47     /**
 48      * Indicates whether this property is required to be set before persisting.
 49      * If YES, then automatically @link M.PresenceValidator is added to the property, to check the presence.
 50      * 
 51      * @type Boolean
 52      */
 53     isRequired: NO,
 54 
 55     /**
 56      * Array containing all validators for this model record property.
 57      * E.g. [@link M.PresenceValidator, @link M.NumberValidator]
 58      * @type Object
 59      */
 60     validators: null,
 61 
 62     /**
 63      * Iterates over validators array and calls validate on each validator with the param object passed to the validator.
 64      * @param {Object} obj The parameter object containing the model id, the record as M.ModelAttribute object and the value of the property.
 65      * @returns {Boolean} Indicates wheter the property is valid (YES|true) or invalid (NO|false).
 66      */
 67     validate: function(obj) {
 68         var isValid = YES;
 69         for (var i in this.validators) {
 70             if(!this.validators[i].validate(obj)) {
 71                isValid = NO; 
 72             }
 73         }
 74         return isValid;
 75     }
 76 });
 77 
 78 //
 79 // CLASS METHODS
 80 //
 81 
 82 /**
 83  * Returns a model attribute.
 84  *
 85  * @param dataType The data type of the attribute: e.g. String 
 86  * @param opts options for the attribute, such as defaultValue, isRequired flag, etc. ...
 87  * @returns {Object} {@link M.ModelAttribute} object
 88  */
 89 M.ModelAttribute.attr = function(dataType, opts) {
 90     if (!opts) {
 91         opts = {};
 92     }
 93     if (!opts.dataType) {
 94         opts.dataType = dataType || 'String';
 95     }
 96 
 97     /* if validators array is not set and attribute is required, define validators as an empty array, (this is for adding M.PresenceValidator automatically */
 98     if (!opts.validators && opts.isRequired) {
 99         opts.validators = [];
100     }
101 
102     /* if model attribute is required, presence validator is automatically inserted */
103     if (opts.isRequired) {
104         /* check if custom presence validator has been added to validators array, if not add the presence validator*/
105         if( _.select(opts.validators, function(v){return v.type === 'M.PresenceValidator'}).length === 0) {
106             opts.validators.push(M.PresenceValidator);
107         }
108     }
109     return this.extend(opts);
110 };