November 3rd, 2011 Category: php5 Programacion
No Comments »

Data Transfer Object

Como nos dice nuestro maestro Martin Fowler, este patron se utiliza para reducir el numero de lladas a un objeto pasando como parametro un objeto que contenga todos los datos necesarios.

Estoy haciendo un mini proyecto, que pronto subire a github para compartir con ustedes (una vez que termine la documentacion :( ), en el cual necesito recibir una cantidad de datos, y para evitar que me pasen muchos parametros, opte por recibir un json, con todos los datos. Ahora el problema es que en ese json la persona que usa el servicio puede mandar parametros de mas, o de menos.

Ahora, para que esto sea algo ordenado, cree un Data Transfer Object, con las propiedades que necesito recibir en el json que me envian como parametro.

El servicio que recibe el json, va a instanciar este Data Transfer Object, y despues vamos a pasarle al modelo al metodo save el objeto completo.

Un paso previo deberia ser validar que los datos que recibo via Json sean correctos una vez que lo paso al DTO.

Supongamos que nuestra funcion encola mails a enviar.

Nuestro DTO sera el siguiente


class Application_Model_Mail_DTO
{
    public $from;
    public $to;
    public $cc;
    public $bcc;
    public $subject;
    public $replyTo;
    public $htmlBody;
    public $textBody;
    public $templateParams;
    public $htmlTemplate;
    public $textTemplate;
}

El metodo que recibe el JSON, seria el sigueinte.

...
public function enqueue($data)
{
    $data = Zend_Json::decode($data);
    $dto = new Application_Model_Mail_DTO();
    $dto->from = $data[‘from’];
    $dto->to = $data[‘to’];
    // … asi sucesivamente hasta cargar todas las propiedades
    $model = new Application_Model_Mail();
    $model->save( $dto );
}        

Ok, esto es bastante tedioso y termina generando un codigo muy largo para algo que podemos resolver en pocas lineas usando SPL.

Las SPL son librerias de PHP compuestas de algunas interfaces y clases, para resolver algunos problemas como el que tenemos en este caso.

Para este caso yo voy a usar ArrayIterator que convierte mi objeto ( DTO ), y lo convierte en iterable. Ademas me va a proporcionar de un metodo vital en este proceso.

Ahora voy a extender mi DTO de ArrayIterator. Y ademas voy a agrgar un hack en el __construct, para que cuando reciba un array, solo guarde los valores que existen como propiedad dentro de mi DTO. La clase quedaria asi.

class Application_Model_Mail_VO extends ArrayIterator
{
    public $from;
    public $to;
    public $cc;
    public $bcc;
    public $subject;
    public $replyTo;
    public $htmlBody;
    public $textBody;
    public $templateParams;
    public $htmlTemplate;
    public $textTemplate;

    public function __construct( $array )
    {
        foreach($array as $key=> $value ) {
            if(property_exists('Application_Model_Mail_VO' , $key )) {
                $this->{$key} = $value;
            }
        }
    }
}

Una vez agregado esto, ahora vamos a ver como quedaria nuestro metodo queue con esta modificacion.

...
public function enqueue($data)
{
    $data = Zend_Json::decode($data);
    $vo = new Application_Model_Mail_DTO( $data );
    $model = new Application_Model_Mail();
    $model->save( $dto );
}

Se daran cuenta que quedo mucho mas simplificado el codigo y mientras mas simple mas facil de leer.

Ahora como quedaria nuestro modelo, que recibe este DTO y lo guarda, en mi ejemplo yo uso MongoDb para no tener que mostrarle el schemea de la Base de Datos, y los metodos inserts de MySql.


class Application_Model_Mails
{
    private $_collection;

    // Insancio la clase Mongo que contiene la conexion, y le digo cual es la coleccion donde voy a guardar los datos.
    public function __construct()
    {
        $db = new Mongo();
        $this->_collection = $db->mailer->spooler;
    }

    public function save( Application_Model_Mail_DTO $properties )
    {
        return $this->_collection->insert( $properties->getArrayCopy()  );
    }
}

Como se ve en el ejemplo, validamos que el parametro que recibe save(), sea una instancia de Application_Model_Mail_DTO, si esto es asi vamos a insertar los parametros que devuelve el metodo getArrayCopy(), que es parte de ArrayIterator, el cual devuelve un array con las propiedades de nuestro Application_Model_Mail_DTO.

Un paso previo, y que no contemple en este ejemplo es validar que los datos que se reciben esten completos y sean validos, tengan en cuenta siempre validar y filtrar los datos que se reciben.


Invitame una Cerverza


Comentar