API Docs for: 1.0.0
Show:

File: Resources/public/js/models/ez-restmodel.js

/*
 * Copyright (C) eZ Systems AS. All rights reserved.
 * For full copyright and license information view LICENSE file distributed with this source code.
 */
YUI.add('ez-restmodel', function (Y) {
    "use strict";
    /**
     * Provides the RestModel abstract class
     *
     * @module ez-restmodel
     */

    Y.namespace('eZ');

    var L = Y.Lang,
        REST_ROOT_LEVEL_SEP = '.';

    /**
     * Abstract class for the model objects loaded from the
     * eZ Publish REST API. It provides some helper methods to deal with type
     * conversions and generic mapping system to map the JSON structure the
     * attributes.
     *
     * @namespace eZ
     * @class RestModel
     * @constructor
     * @extends Model
     */
    Y.eZ.RestModel = Y.Base.create('restModel', Y.Model, [], {
        /**
         * Setter function for the boolean attribute.
         * Makes sure the string "true" is tranformed to true,
         * any other value (except a boolean value) is considered
         * as false
         *
         * @method _setterBoolean
         * @protected
         * @param {Any} val the value to transform
         * @return {Boolean}
         */
        _setterBoolean: function (val) {
            if ( L.isBoolean(val) ) {
                return val;
            }
            return val === 'true';
        },

        /**
         * Setter function for the date attribute.
         * Make sure to transform the string input value into a date.
         *
         * @method _setterDate
         * @protected
         * @param {String} val the value to transform
         * @return {Date}
         */
        _setterDate: function (val) {
            var parsed;

            if ( val instanceof Date ) {
                return val;
            }
            parsed = Date.parse(val);
            if ( !isNaN(parsed) ) {
                return new Date(val);
            }
            return new Date();
        },

        /**
         * Setter function for the localized attribute.
         * It transforms any value like
         *
         *     {
         *        value: [{
         *            '_languageCode': 'fre-FR',
         *            '#text': "Français"
         *        }, {
         *            '_languageCode': 'eng-GB',
         *            '#text': "English"
         *        }]
         *     }
         *
         * into:
         *
         *     {
         *         'fre-FR': 'Français',
         *         'eng-GB': 'English'
         *     }
         *
         * @method _setterLocalizedValue
         * @protected
         * @param {Object} val the localized object to transform
         * @return {Object}
         */
        _setterLocalizedValue: function (val) {
            var res = {};

            if ( !L.isObject(val) ) {
                return Y.Attribute.INVALID_VALUE;
            }
            if ( L.isArray(val.value) ) {
                Y.Array.each(val.value, function (item) {
                    res[item._languageCode] = item["#text"];
                });
            }
            return res;
        },

        /**
         * Parses the hash returned by the eZ Publish REST API
         * based on ATTRS_REST_MAP and LINKS_MAP properties
         *
         * @protected
         * @method _parseStruct
         * @param {Object} struct the struct to transform
         * @param {Object} doc The complete object
         * @return {Object}
         */
        _parseStruct: function (struct, doc) {
            var attrs = {},
                links = {};

            Y.Array.each(this.constructor.ATTRS_REST_MAP, function (item) {
                var key;

                if ( L.isString(item) ) {
                    // simple mapping
                    attrs[item] = struct[item];
                } else if ( L.isObject(item) ) {
                    // translating the identifier in the result struct
                    key = Y.Object.keys(item)[0];
                    attrs[item[key]] = struct[key];
                }
            });
            Y.Array.each(this.constructor.LINKS_MAP, function (item) {
                if ( struct[item] ) {
                    links[item] = struct[item]._href;
                }
            });
            attrs.resources = links;
            return attrs;
        },

        /**
         * Parses an object (usually a response object from the JS REST client)
         *
         * @method parse
         * @param {Object} response an object with a `document` property holding
         * the struct to parse like the response object from the eZ JS REST
         * Client
         * @return {Object} attribute hash
         */
        parse: function (response) {
            var content = response.document,
                root = this.constructor.REST_STRUCT_ROOT;

            if ( root ) {
                Y.Array.each(root.split(REST_ROOT_LEVEL_SEP), function (val) {
                    content = content[val];
                });
            }
            return this._parseStruct(content, response.document);
        },

        /**
         * Loads the model from a simple literal object. It applies
         * the mapping described by the ATTRS_REST_MAP and LINKS_MAP.
         *
         * @method loadFromHash
         * @param {Object} hash a literal object to import
         */
        loadFromHash: function (hash) {
            var root = this.constructor.REST_STRUCT_ROOT,
                doc = {},
                tmp = doc;

            if ( root ) {
                Y.Array.each(root.split(REST_ROOT_LEVEL_SEP), function (val) {
                    tmp[val] = {};
                    tmp = tmp[val];
                });
            }
            tmp = hash;
            this.setAttrs(this._parseStruct(hash, doc));
        },

        /**
         * Overrides the default implementation to make sure the id is also
         * resetted to its default value (null) when necessary.
         * It's a workaround for https://github.com/yui/yui3/issues/1982 which
         * causes https://jira.ez.no/browse/EZP-23584
         *
         * @method reset
         * @param {String} [name] The name of the attribute to reset. If
         * omitted, all attributes are reset.
         * @return {Model} A reference to the host object.
         */
        reset: function (name) {
            var ret = Y.Model.superclass.reset.call(this, name);
            if ( !name || name === 'id' ) {
                this.set('id', null);
            }
            return ret;
        },

        /**
         * Overrides the default implementation to make sure the models in
         * attributes are also jsonified.
         *
         * @method toJSON
         * @return {Object}
         */
        toJSON: function () {
            var attrs = Y.Model.prototype.toJSON.call(this);

            Y.Object.each(attrs, function (value, key) {
                if ( L.isObject(value) && L.isFunction(value.toJSON) ) {
                    attrs[key] = value.toJSON();
                }
            });
            return attrs;
        },
    }, {
        /**
         * Root element in the REST API response where the data is located.
         * It can contains points to target a deep structure.
         *
         * @static
         * @property REST_STRUCT_ROOT
         * @type string
         * @default ""
         */
        REST_STRUCT_ROOT: "",

        /**
         * Mapping between properties in a hash structure
         * and the attributes of the model object. Each element can be
         * a string or a hash with one pair key/value.
         * A string means a simple mapping between the rest structure
         * property and the attribute. The simple hash allows to have
         * a different attribute identifier than the property name.
         * Example:
         *
         *     // REST structure
         *     {"name": "my name", "id": 42}
         *
         * With the following map:
         *
         *     ["name", {'id': 'myId'}]
         *
         * Would result in the following hash:
         *
         *     {"name": "my name", "myId": 42}
         *
         * when parsed in the _parseStruct method.
         *
         * @static
         * @property ATTRS_REST_MAP
         * @type Array
         */
        ATTRS_REST_MAP: [],

        /**
         * Array of linked resources to parse and make available
         * in the resources attribute
         * Example:
         *
         *     ['Owner', 'MainLocation']
         *
         * @static
         * @property LINKS_MAP
         * @type Array
         */
        LINKS_MAP: [],

        ATTRS: {
            /**
             * Contains the URI to linked resources
             * Example:
             *
             *     {
             *        Owner: '/api/ezp/v2/user/users/14',
             *        MainLocation: '/api/ezp/v2/content/locations/1/2/61'
             *     }
             *
             * @attribute resources
             * @type Object
             * @default {}
             */
            resources: {
                value: {}
            }
        }
    });
});