Comunidad de diseño web y desarrollo en internet online

Clase para convertir tipos de datos en Flex

Si utilizamos Flex con un servidor ColdFusion o Java (si tenemos dinero para pagarlo) podemos hacer clases ValueObject (clases que sólo tienen propiedades y se encargan de transmitir datos entre el servidor y diferentes puntos de la aplicación) en esos lenguajes que se correspondan con las de Flex, de manera que puedo enviar un objeto de la clase ContactoVO en Java y recibirlo como objeto ContactoVO en Flex.

Sin embargo en PHP no tenemos esa opción, es decir, lo que recibiremos del servidor en la mayor parte de los casos será un objeto del tipo Object, y en Flex tendremos que encargarnos de parsearlo para que sea una instancia de nuestra clase. Podemos hacerlo a mano, más o menos así:

Código :

//Aquí recibimos los datos del servidor
public function result(data:Object):void
      {
         for each (var item : Object in data.result.categories)
         {            
            var category:CategoryVO = new CategoryVO ();
            category.name = item.name;
            category.tags = new ArrayCollection(item.tags);
            category.versions = item.versions;
            ...
         }
         ...


Sin embargo, esto puede hacerse muy tedioso, y no podemos usar el operador as ya que solo funciona con clases que tienen "parentesco". Mediante este operador se puede relacionar un Array con un ArrayCollection, o un int y un Number, pero no un Object con una clase creada por nosotros.

Para hacer esto más rápido, Dano aportó una solución: Una clase a la que pasamos como parámetros el objeto que queremos parsear, y la clase que queremos (ya que en AS3 existe el tipo de datos Class), y usando un for in, que en cada iteración, iguala la variable que le pasamos a una cadena con el nombre una propiedad del objeto que analizamos, de manera que podemos acceder a ella usando la sintaxis objeto[variable]; y la propiedad hasOwnProperty, que tienen todos los objetos de ActionScript 3 podamos obtener una instancia del objeto parseado:

Código :

package com.cristalab.resourcebrowser.utils
{
   /**Esta clase contiene funciones para la conversión de distintos tips de datos.*/
   public class DataConvert
   {      
      /**Esta función sirve para convertir un objeto cualquiera
      * en una instancia de una clase.
      * @param value El objeto que queremos parsear.
      * @param tClass  El nombre de la clase en la que queremos transformar el objeto.
      * @return Una instancia de la clase que hemos pedido */
      public static function objectToClass(value:Object, tClass:Class):Object
      {         
         //Creamos una instancia de la clase
         var newClass:Object;
         newClass = new tClass();      
      //Usamos el bucle "for in", que nos permitirá recorrer tanto
      // las propiedades del objeto, como sus valores.
         for(var i:String in value)
         {
            //Usamos la función de la clase Object hasOwnProperty para
            //saber si hemos definido esa propiedad en la clase.
            if( newClass.hasOwnProperty(i) )
            {
               try
               {
                     //Le asignamos las propiedades del objeto 
                     //a la nueva instancia de la clase.
                  tClass(newClass)[i] = value[i];
                  
               }
               catch(err:Error)
               {
                    //Si estamos tratando de parsear una propiedad con un tipo de
                    //datos distinto, mostramos un error.
                  throw new Error("Error setting " + i + " to the new class. Incompatible datatypes. \n" + err.message);
               }
            }
         }         
         return newClass;
      }
   }
}


Ahora podemos hacer lo mismo de antes bastante más rápido:

Código :

...
for each (var item : Object in data.result.categories)
         {            
            var category : CategoryVO = DataConvert.objectToClass(item,CategoryVO) as CategoryVO;
            //var category:CategoryVO = new CategoryVO ();
            //category.name = item.name;
            //category.tags = new ArrayCollection(item.tags);
            //category.versions = item.versions;
            ...            
         }
...


Sin embargo, podemos encontrarnos con situaciones en las que el tipo de datos no sea exactamente el mismo (por ejemplo, si quiero manejar ArrayCollections en lugar de Arrays para manejar mejor los dataProviders de los componentes.

Para ello podemos aplicar Reflection. Para aprender sobre qué es eso, mejor lean el artículo de Madeinflex, pero vamos a quedarnos con que nos da un xml que permite conocer la estructura de una clase en tiempo de ejecución, eso sí, siempre que esté importada y con instancias de las clases que necesitamos (tal como también explican en el artículo). De modo que la clase quedaría así:

Código :

package com.cristalab.resourcebrowser.utils
{
   import com.cristalab.resourcebrowser.utils.ClassLinker
   import flash.utils.describeType;
   import flash.utils.getDefinitionByName   
   
   /**Esta clase contiene funciones para la conversión de distintos tips de datos.*/
   public class DataConvert
   {      
      /**Esta función sirve para convertir un objeto cualquiera
      * en una instancia de una clase.
      * @param value El objeto que queremos parsear.
      * @param tClass  El nombre de la clase en la que queremos transformar el objeto.
      * @return Una instancia de la clase que hemos pedido */
      public static function objectToClass(value:Object, tClass:Class):Object
      {         
         //Creamos una instancia de la clase
         var newClass:Object;
         newClass = new tClass();      
      //Usamos el bucle "for in", que nos permitirá recorrer tanto
      // las propiedades del objeto, como sus valores.
         for(var i:String in value)
         {
            //Usamos la función de la clase Object hasOwnProperty para
            //saber si hemos definido esa propiedad en la clase.
            if( newClass.hasOwnProperty(i) )
            {
               try
               {                  
                  //Sacamos cual va a ser el tipo de la variable de la clase usando la sintaxis 
                //E4X de AS3
                  var targetType : Class = getDefinitionByName (String(describeType (newClass).accessor.(@name == i).@type)) as Class;
                
                      tClass(newClass)[i] = value[i] as targetType;
                  
                     //Le asignamos las propiedades del objeto 
                     //a la nueva instancia de la clase, intentando que sea del tipo
                     //apropiado.            
               }
               catch(err:Error)
               {
                    //Si estamos tratando de parsear una propiedad con un tipo de
                    //datos distinto, mostramos un error.
                  throw new Error("Error setting " + i + " to the new class. Incompatible datatypes. \n" + err.message);
               }
            }
         }         
         return newClass;
      }
   }
}


donde ClassLinker sería algo como:

Código :

package com.cristalab.resourcebrowser.utils
{
   import com.cristalab.resourcebrowser.vos.CategoryVO;
   import mx.collections.ArrayCollection;
   import mx.collections.ListCollectionView;
   
   public class ClassLinker
   {
      private var category : CategoryVO
      private var coll : ArrayCollection
      private var list : ListCollectionView;      
   }
}


Espero que les haya servido.

¿Sabes SQL? ¿No-SQL? Aprende MySQL, PostgreSQL, MongoDB, Redis y más con el Curso Profesional de Bases de Datos que empieza el martes, en vivo.

Publica tu comentario

o puedes...

¿Estás registrado en Cristalab y quieres
publicar tu URL y avatar?

¿No estás registrado aún pero quieres hacerlo antes de publicar tu comentario?

Registrate