Home Manual Reference Source Test Repository

src/Serializer/Serializer.js

/*
 * This file is part of the serializerjs package.
 *
 * (c) HAIRCVT <tfidry@haircvt.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

import SerializerAware from './SerializerAware';
import SerializerInterface from './SerializerInterface';
import SerializationError from './../Error/SerializationError';
import InvalidArgumentError from './../Error/InvalidArgumentError';

/**
 * Default serializer.
 *
 * Meant to aggregate all the application serializers and be used as the main serializer in the application. This means
 * that for serializing a new object, a custom serializer for this one should be done and registered to this serializer.
 *
 * @author Théo FIDRY <theo.fidry@gmail.com>
 */
export default class Serializer extends SerializerInterface {
    /**
     * @param {Map.<string,SerializerInterface>} serializers
     *
     * @throw InvalidArgumentError
     */
    constructor(serializers) {
        super(serializers);

        for (const serializer of serializers.values()) {
            if (false === serializer instanceof SerializerInterface) {
                throw new InvalidArgumentError(
                    `Expected serializer to implement SerializerInterface. Got ${serializer.constructor} instead`
                );
            }

            if (serializer instanceof SerializerAware) {
                serializer.setSerializer(this);
            }
        }

        /**
         * @type {Map.<string, SerializerInterface>}
         * @private
         */
        this._serializers = serializers;
    }

    /**
     * @inheritDoc
     */
    serialize(data, format, context) {
        const serializer = this._getSerializerForSerialization(data, format);
        if (null !== serializer) {
            return serializer.serialize(data, format, context);
        }

        throw new SerializationError(`An unexpected value could not be serialized: "${data}"`);
    }

    /**
     * @inheritDoc
     */
    supportsSerialize(data, format = null) {
        return null !== this._getSerializerForSerialization(data, format);
    }

    /**
     * @inheritDoc
     */
    deserialize(data, className, format = null, context = null) {
        const serializer = this._getSerializerForDeserialization(data, className, format);
        if (null !== serializer) {
            return serializer.deserialize(data, className, format, context);
        }

        throw new SerializationError(`An unexpected value could not be deserialized: "${data}"`);
    }

    /**
     * @inheritDocz
     */
    supportsDeserialize(data, className, format = null) {
        return null !== this._getSerializerForDeserialization(data, className, format);
    }

    /**
     * @param {*}       data          Any data
     * @param {?string} [format=null] Format the normalization result will be encoded as
     *
     * @return {?SerializerInterface}
     * @private
     */
    _getSerializerForSerialization(data, format = null) {
        for (const serializer of this._serializers.values()) {
            if (true === serializer.supportsSerialize(data, format)) {
                return serializer;
            }
        }

        return null;
    }

    /**
     * @param {*}       data          Data to restore
     * @param {string}  className     The expected class to instantiate
     * @param {?string} [format=null] Format the given data was extracted from
     *
     * @return {?SerializerInterface}
     * @private
     */
    _getSerializerForDeserialization(data, className, format = null) {
        for (const serializer of this._serializers.values()) {
            if (true === serializer.supportsDeserialize(data, className, format)) {
                return serializer;
            }
        }

        return null;
    }
}