26 sept 2009

WebServices con NuSOAP en PHP - Ejemplo 2

En este segundo ejemplo de WebServices con PHP utilizando NuSOAP como biblioteca, voy a mostrar un ejemplo un poco más complejo que el del post anterior (WebServices con NuSOAP en PHP - Ejemplo 1). En este nuevo ejemplo voy a añadir un objeto "Cliente" en el servidor, el cual va a ser devuelto al consumidor/cliente del webservice (previa conversión del objeto a un vector). Para que quede más en claro, comenzare por los ejemplos del servidor y el cliente.

El servidor

Al ser un ejemplo un poco más complejo decidí agregar algunos comentarios más para que el código sea un poco más legible. Igualmente luego del código comentaré algunos fragmentos de código más en detalle.
 

<?php
// Importar la biblioteca NuSOAP
require_once('nusoap/lib/nusoap.php');
$miURL = 'http://pruebas.orlandobrea.com.ar/nusoap';
$server = new soap_server();
$server->configureWSDL('ws_orlando', $miURL);
$server->wsdl->schemaTargetNamespace=$miURL;

/*
* Ejemplo 2: getCliente es una funcion mas compleja que recibe un id y retorna el cliente
* que le corresponde (solo retorna 2 clientes). Tener en cuenta que las respuestas del
* WebService son un Array (vector) y no un objeto propiamente dicho. Si deseamos recuperar
* el objeto del lado del cliente, lo debemos convertir de vector a objeto. En el ejemplo 3
* se ampliara sobre este tipo de operaciones.
*/
// El objeto que voy a enviar al cliente como respuesta
class Cliente {
var $id;
var $nombre;
var $apellido;
var $cuit;
}
// Un objeto de acceso a datos (DAO - Data Access Object) que es el encargado de
// administrar los objetos almacenados (en este caso todos los valores estan
// prefijados, pero en un ejemplo real se podrian obtener de una base de datos)
class ClienteDAO {
/**
* getCliente($id) : Cliente
* Esta funcion deberia implementarse con una conexion a una base de datos
* y obtener la informacion de la base directamente
*/
function getCliente($id) {
$obj = new Cliente();
if ($id==1) {
$obj->id = 1;
$obj->nombre = 'Blas';
$obj->apellido = 'Pascal';
$obj->cuit = '11-11111111-1';
}
if ($id==2) {
$obj->id = 1;
$obj->nombre = 'Isaac';
$obj->apellido = 'Newton';
$obj->cuit = '22-22222222-2';
}
return $obj;
}
}
// Creo la estructura en la cual voya convertir al objeto Cliente, para enviarlo al
// consumidor del WebService (En este caso contiene un vector con id, nombre, apellido
// y cuit)
$server->wsdl->addComplexType('Cliente',
'complexType',
'struct',
'all',
'',
array(
'id' => array('name' => 'id', 'type' => 'xsd:int'),
'nombre' => array('name' => 'nombre', 'type' => 'xsd:string'),
'apellido' => array('name' => 'apellido', 'type' => 'xsd:string'),
'cuit' => array('name' => 'CUIT', 'type' => 'xsd:string')
)
);
// Registro la funcion que se expone en el webservice, la que puede consumir el cliente,
// e indico a que funcion PHP se debe llamar cuando el cliente invoque el webservice
// (getCliente)
$server->register('getCliente', // Nombre de la funcion
array('id' => 'xsd:int'), // Parametros de entrada
array('return' => 'tns:Cliente'), // Parametros de salida
$miURL
);
// Funcion que es llamada por el WebService de NuSOAP cuando el cliente intenta consumir
// el servicio web expuesto
function getCliente($id) {
$dao = new ClienteDAO();
$cliente = $dao->getCliente($id);
// Convierto el objeto en un vector, con una key por cada propiedad del objeto
$respuesta = array('id'=> $cliente-id,
'nombre' => $cliente->nombre,
'apellido' => $cliente->apellido,
'cuit' => $cliente->cuit
);
// Indico que el parametro de respuesta es del tipo tns:Cliente, y cual es el vector
// que contiene dicha estructura
return new soapval('return', 'tns:Cliente', $respuesta);
}

$server->service($HTTP_RAW_POST_DATA);
?>

En el códido de este nuevo ejemplo, existen algunas diferencias con respecto al del ejemplo1, por eso voy a intentar detallar cada una de ellas con un poco de detalle, para poder explicar de que se trata cada una de las nuevas incorporaciones.

Creamos un objeto Cliente

En este nuevo módulo servidor utilizamos una clase llamada "Cliente" que es la que luego de ser convertida, será devuelta al cliente/consumidor del WebService. Decidí crear una clase, para hacer el ejemplo un poco más acorde a lo que nos encontraremos en la vida cotidiana, es decir, hoy en día estamos muy acostumbrados a trabajar con objetos, y que toda la información que tengamos disponibles en nuestros sistemas se encuentren representadas por objetos. Es por eso, que comence  incorporar los objetos al ejemplo. La definición de la clase es la siguiente:

class Cliente {
var $id;
var $nombre;
var $apellido;
var $cuit;
}

Es un objeto muy simple, el cual no tiene asociaciones con otros objetos, simplemente tiene 4 atributos:

  • id
  • nombre
  • apellido
  • cuit

Si bien el objeto es muy simple, nos servirá para poder comenzar a ver cuales son las implicancias del mismo y como debemos convertirlo para luego retornarlo el cliente del webservice.

Creamos un objeto ClienteDAO

Siguiendo con la esta nueva meta de acercar el ejemplo a la vida real, incorporé un objeto DAO (Data Access Object). Para aquellos que no conocen o no están acostumbrados a usar un DAO, voy a intentar definirlo con unas pocas palabras. Cuando creamos aplicaciones multicapa, algo muy común hoy en día, es normal que una de las capas se llame DAO, que podríamos traducir como Capa de Acceso a Datos. Esta capa de acceso a datos, es la encargada de manejar los datos de la aplicación, por ejemplo la que se encarga de leer, guardar y borrar datos de un origen de datos, como podría ser una base de datos, un archivo XML, u otro webservice. Esta capa nos permite abstraer toda la lógica de acceso a datos, para que, si el día de mañana decidimos cambiar de motor de base de datos, o de origen de datos, no tengamos que modificar todas las demás partes del código, solamente cambiamos las clases de esta capa. Generalmente se utiliza un objeto DAO por cada objeto del dominio que queremos guardar/modificar/borrar (existen formas de agrupar en un único objeto las operaciones sobre varios objetos del dominio, pero es dependiente del lenguaje, y prefiero no ahondar en ello para no complicar el ejemplo).

Ya explicado, muy brevemente, que es un DAO vamos a la definición de la clase ClienteDAO:

class ClienteDAO {
/**
* getCliente($id) : Cliente
* Esta funcion deberia implementarse con una conexion a una base de datos
* y obtener la informacion de la base directamente
*/
public function getCliente($id) {
$obj = new Cliente();
if ($id==1) {
$obj->id = 1;
$obj->nombre = 'Blas';
$obj->apellido = 'Pascal';
$obj->cuit = '11-11111111-1';
}
if ($id==2) {
$obj->id = 1;
$obj->nombre = 'Isaac';
$obj->apellido = 'Newton';
$obj->cuit = '22-22222222-2';
}
return $obj;
}
}

Simplemente definimos un método, getCliente, para el objeto que crearemos. Para mantener el ejemplo sencillo, la información retornada por el mismo esta pre-fijada, es decir, no es tomada desde una base de datos, u otra fuente, como si sería en una aplicación del mundo real. Si este método lo implementaramos en una aplicación real, ejecutariamos una sentencia SQL similar a "select * from Cliente where id=".$id y luego convertiriamos la respuesta en un objeto Cliente que es el que retornamos.

Dado que es un ejemplo sin conexión con un origen de datos, esta simple función puede retornar solo 2 objetos clientes, uno para cuando se le pasa como parámetro 1, y otro para cuando se pasa como parámetro 2. En caso de pasar cualquier otro valor como parámetro la función retornará un objeto Cliente sin inicializar sus atributos.

Definimos el tipo de datos devuelto por el WebService

A diferencia del ejemplo 1, en el cual nuestro WebService solo retornaba un String (xsd:string), en esta oportunidad nuestro WebService, retornará un objeto (representado en un vector). Pero como estamos retornando un valor complejo, es decir, no es un string, o int, u otro tipo que ya este predefinido, debemos definirlo nosotros, para ello usamos el siguiente ceodigo:


En el código, estamos informandole a nuestro objeto $server, que utilizaremos un tipo de datos propio, o tipo complejo (este tipo de datos complejo se reflejará en nuestro WSDL del WebService). Los parámetros que más nos interesan para la función "addComplexType" son el primero, y el último. 

El primer parámetro define cual es el nombre que le asignamos a este tipo de datos complejo, en este caso "Cliente".

El último parámetro define como esta compuesto este tipo de datos complejo. Como podemos ver en el ejemplo, el tipo de datos se define como un array (vector) el cual esta compuesto por varios elementos (id, nombre, apellido, cuit), y cada uno de dichos elementos debe tener un vector que contenga "name" y "type" es decir la definición para cada tipo de datos que compone este tipo complejo. Lo que hacemos, no es más que definir un tipo de datos complejo, compuesto por diferentes tipos de datos simples (con simple, me refiero a aquellos que son los estandares) y/o otros tipos de datos complejos que ya hayan sido definidos. Es similar a la definición de una estructura de datos, u objeto. Debemos tener en cuenta que los tipos de datos simples tienen el prefijo xsd (recordarlo para incorporarlo a cada tipo que estamos definiendo).

Registración de la función a exponer

Al igual que en el ejemplo 1, debemos exponer cuales funciones deseamos publicar en nuestro WebService, para ello llamamos al método "register" de nuestro objeto $server, como podemos ver en el siguiente código:

$server->register('getCliente', // Nombre de la funcion
array('id' => 'xsd:int'), // Parametros de entrada
array('return' => 'tns:Cliente'), // Parametros de salida
$miURL
);

La registración de la función expuesta, es muy similar al ejemplo 1, la única diferencia es que en vez de retornar un tipo de datos xsd:string, retornamos un tipo de datos complejo tns:Cliente. Este tipo de datos, es el que definimos en el punto anterior. Con los últimos 2 puntos le estamos indicando a NuSOAP que vamos a retornar un tipo de datos complejo, el cual tiene la estructura definida en tns:Cliente (estructura definida en el punto anterior). 

Función que retorna el cliente

Al igual que en el ejemplo anterior tenemos una función que es la encargada de procesar el pedido y retornar la respuesta. En este caso dicha función se llama getCliente y es la siguiente:

function getCliente($id) {
$dao = new ClienteDAO();
$cliente = $dao->getCliente($id);
// Convierto el objeto en un vector, con una key por cada propiedad del objeto
$respuesta = array(
'id'=> $cliente->id,
'nombre' => $cliente->nombre,
'apellido' => $cliente->apellido,
'cuit' => $cliente->cuit
);
// Indico que el parametro de respuesta es del tipo tns:Cliente, y cual es el vector
// que contiene dicha estructura
return new soapval('return', 'tns:Cliente', $respuesta);
}

Al estar utilizando objetos para obtener los datos que deseamos retornar, tenemos algunos pasos más en al función que en el ejemplo anterior. 

  • Definimos en objeto $dato que es del tipo ClienteDAO (la capa de acceso a datos).
  • Obtenemos el cliente con el $id pasado como parámetro, a través del objeto DAO que creamos en el primer paso.
  • Convertimos el objeto cliente en un vector para luego poder retornarlo (usamos como key, el nombre de cada uno de los atributos del objeto).
  • Retornamos el vector, informando que el mismo es del tipo tns:Cliente (es decir, le pedimos a NuSOAP que nos cree un tns:Cliente a partir del vector pasado como parámetro.

¿Como creo el mapeo entre el objeto y el vector?

Para alcanzar este objetivo, cada uno puede tener sus preferencias, yo utilizó una correspondencia 1 a 1, entre el nombre del atributo y la key del vector. Ejemplo:

class Cliente { $vector = array(
var $id; --------> 'id' => '',
var $nombre; --------> 'nombre' => '',
var $cuit; --------> 'cuit' => ''
} );

Como vemos en el ejemplo, la propiedad id del objeto Cliente, se corresponde con la key 'id' del vector $vector. Cuando el objeto es copiado al vector, al acceder a $cliente->id; PHP no da el mismo valor que $vector['id'];

Cliente

El cliente no tiene mayores modificaciones que el del ejemplo 1, simplemente modifica el nombre del script del servidor, y la función a la cual se llama en el mismo.

<?php
require_once('nusoap/lib/nusoap.php');
// Crear un cliente apuntando al script del servidor (Creado con WSDL)
$serverURL = 'http://pruebas.orlandobrea.com.ar';
$serverScript = 'nusoap_server_ej2.php';
$metodoALlamar = 'getCliente';

$cliente = new nusoap_client("$serverURL/$serverScript?wsdl", 'wsdl');
// Se pudo conectar?
$error = $cliente->getError();
if ($error) {
echo '<pre style="color: red">' . $error . '</pre>';
echo '<p style="color:red;'>htmlspecialchars($cliente->getDebug(), ENT_QUOTES).'</p>';
die();
}


// 2. Llamar a la funcion getCliente del servidor
$result = $cliente->call(
"$metodoALlamar", // Funcion a llamar
array('id' => '1'), // Parametros pasados a la funcion
"uri:$serverURL/$serverScript", // namespace
"uri:$serverURL/$serverScript/$metodoALlamar" // SOAPAction
);
// Verificacion que los parametros estan ok, y si lo estan. mostrar rta.
if ($cliente->fault) {
echo '<b>Error: ';
print_r($result);
echo '</b>';
} else {
$error = $cliente->getError();
if ($error) {
echo '<b style="color: red">Error: ' . $error . '</b>';
} else {
echo 'Respuesta: ';
print_r($result);
}
}
?>

El cliente es muy sencillo, ya que simplemente muestra el contenido de la respuesta del servidor. En un ejemplo del mundo real, el vector que nos devuelve el servidor, lo deberíamos convertir a un objeto cliente (haciendo el mapeo inverso. Antes pasamos del objeto a un vector, y ahora deberíamos pasar del vector a un objeto). En el ejemplo 4, voy a hacer el cliente un poco más complejo, convirtiendo del vector a un objeto, y luego operando con el objeto.

Conclusión

En este ejemplo el servidor fué el que recibió modificaciones, para poder comenzar a operar con objetos, pero el cliente lo mantuve igual de simple que en el ejemplo anterior. También podés descargar el archivo comprimido con el ejemplo. Como vemos a medida que vamos aproximando nuestro ejemplo a la vida real, el mismo se hace un poco más complejo y debemos utilizar diferentes conocimientos que a veces escapan al del WebService en si. 

20 sept 2009

MAC OS X - Reemplazar una carpeta borra la anterior

Todos aquellos que comenzamos a trabajar con OS X en el último tiempo, en algún momento vamos a tener que copiar una carpeta sobre otra, y a diferencia de otros sistemas operativos, OS X realmente reemplaza la anterior por la nueva carpeta.
Cuando arrastramos una carpeta y dicha carpeta ya existe, el sistema operativo OS X nos pregunta si deseamos reemplazar la carpeta, yo (como muchas otras personas) entendemos por reeemplazar el mantener el solo reemplazar los archivos que ya existen por los nuevos, y no eliminar la carpeta anterior, para reemplazarla por la nueva que estamos copiando.
No recuerdo si esto era así en OS 8 y OS 9, ya hace tanto tiempo que no los uso, pero no recuerdo haber tenido este inconveniente.

Tome algunas capturas de pantallas, para poder entender mejor cual es el inconveniente, dicen que una imagen vale más que mil palabras, en una imagen no pude describir todo el proceso, entonces, tendremos que conformarnos con varias imagenes.

Paso 1

Primero cree una carpeta para el ejemplo, la cual se llama Documentos.

Paso 2

Esta es la carpeta que deseamos copiar en la anterior.

Paso 3

Arrastramos la carpeta nueva, en la carpeta vieja. Si estamos acostumbrados a otros sistemas operativos, solo debemos arrastrar la carpeta nueva a la carpeta que deseamos reemplazar.

Paso 4

El sistema operativo OS X nos solicitá que confirmemeos que deseamos reemplazar la carpeta destino, por la nueva carpeta. Uno tiende a pensar (al menos yo) que lo que va a hacer es reemplazar todos los archivos que se encuentran en la carpeta destino, y que existen en la carpeta origen.

Paso 5

En esta imagen vemos como quedo la carpeta destino. Como podemos ver, los archivos creados anteriormente ya no existen. MAC OS-X eliminó los archivos anteriores, y los reemplazo por los archivos de la carpeta origen.

¿Que me pasó?

Dado que yo no sabía de esta "sutileza" de OS X, perdí toda la carpeta de instalación de Drupal. Tenía que actualizar Drupal a una nueva versión, entonces simplemente hice drag and drop desde la nueva versión que descargue de Drupal, en el directorio del sitio que estaba desarrollando. Como elimina los archivos y carpetas anteriores, perdí todos lo módulos que tenía instalados, y algunos en los cuales estaba desarrollando.

Debo ser sincero, que cuando me paso esto, no dije "Que bueno que es el MAC OS-X" sino todo lo contrario. Desde el punto de vista de usabilidad me parece un gran error, que me extraña de la gente de Apple, que siempre se caracteriza por facilitarle la vida al usuario (en este caso, no lo lograron).

Alternativa para copiar sin borrar

En caso que deseen copiar una carpeta en otra, sin perder los datos de la carpeta anterior, lo que deben hacer es ir a la linea de comandos y escribir la siguiente sentencia:

cp -R <directorio origen> <directorio destino>

Espero que sea de utilidad para prevenir a alguien de perder algún dato. En caso que ya sea tarde, te recomiendo que busques alguna herramienta de recuperación de datos (a mi no me funcionó, pero a algunas personas parece que sí).


16 sept 2009

Gran crecimiento de Lorena en Brilla con MaryKay

Estoy sorprendido por la capacidad de emprendimiento que tiene Lorena, podemos ver en Brilla con MaryKay como en solo unas pocas semanas de haber comenzado su emprendimiento como consultora de belleza independiente ya tiene su sitio web, sigue cargando información, y por sobre todas las cosas, tiene promociones muy interesantes durante el mes de septiembre.

Ahh, también ya esta cargando las promociones que se ven presentando en Twitter, la podes seguir en @BrillaConMK.

Espero que siga progresando y trabajando tanto como hasta ahora, seguramente muy pronto llegará a ser directora. Es un claro ejemplo que si se quieren realizar las cosas, se pueden realizar, solo es cuestión de hacerlas con ganas.

14 sept 2009

Serie de TV "Shark Tank" - Emprendedores vs Inversores

Hoy descubrí una serie de TV gracias a Twitter, una de las personas que sigo en dicha red @StartupPro publico un tweet de un show de televisión llamado "Shark Tank" (que sería "Tanque de tiburones"). A pesar de su nombre, no tiene nada que ver con los tiburones reales, sino con un grupo de 5 inversionistas que escuchan a emprendedores vender sus ideas.

El show consiste en que hay 5 inversores dispuestos a escuchar propuestas de los emprendedores que asisten al show. Cada emprendedor tiene un tiempo reducido para presentar sus ideas. Luego de que el emprendedor presenta su idea, los inversores deciden si les parece que es una buena idea como para invertir en ella, y las capacidades del emprendedor. Al igual que en la vida real, evalúan no solo la idea y si económicamente les resulta conveniente, sino que también evalúan que tan preparado esta el emprendedor para llevarla a cabo. Como sabemos, es un conjunto, la idea debe ser económicamente redituable (y financiaramente) así como también la persona que la llevará a la práctica debe estar capacitada y dispuesta a dar todo de ella para llegar a la meta.

El comportamiento es muy parecido a el de los inversores ángeles o angel inverstors, en el cual el emprendimiento aún no esta en funcionamiento o es muy reciente, siendo difícil acudir a entidades bancarias. Por tal motivo, y como generalmente pasa en estos tipos de inversiones, se busca obtener la mayor participación posible en el emprendimiento por parte del inversor. Es decir, el inversor quiere tener la mayor participación en las decisiones posibles, ya que al invertir una suma importante de dinero, y teniendo garantías nulas o casi nulas, se debe asegurar que la persona haga lo mejor para cumplir con el objetivo, y en caso que se este desviando o piense que la mejor alternativa puede ser otra, poder modificar el rumbo del emprendimiento.

Este tipos de inversiones son duras para ambas partes, el inversor arriesga mucho dinero, sin una garantía real, mientras que el emprendedor, da "todo" su tiempo intentando cubrir las expectativas planteadas.

Volviendo al show, si bien esta un poco preparado para la TV, es bastante duro, pero esta muy bueno para poder ver cual es la visión de cada una de las partes. Como cada persona defiende sus intereses y hasta que punto cada parte esta dispuesta a ceder. Cual es el limite de cada parte. También es interesante poder ver las diferentes ideas que tienen las personas, algunas muy raras, otras que no parecen negocio (no me animo a decir que no lo son, ya que hasta no llevarlo a la práctica muchas veces nos pueden sorprender), unas interesantes, otras no tanto, en fin hay de todo.

Para todos aquellos que deseen conocer más sobre el show, pueden visitar la página del mismo en Shark Tank en ABC, si no estas en Estados Unidos, no vas a poder ver el show, pero por suerte, en YouTube existen varios episodios. Sino también podes buscar en google shark tank.

8 sept 2009

Emprendimientos - 10 puntos para verificar la realidad

Este post es una traduccion del post de Martin Zwilling (Entrepreneurs: Ten-Point Reality Check). El post original en ingles lo podes encontrar en http://blog.startupprofessionals.com/2009/09/entrepreneurs-ten-point-reality-check.html. Este post se refiere al libro de Guy Kawasaki "Reality Check: The Irreleverent Guide to Outsmarting, Outmanaging, and Outmarketing Your Competition".

Quiero agradecer especialmente a Martin por haberme permitido realizar la traduccion de su post.

10 puntos para verificar la realidad en emprendimientos

Estos son una serie de puntos a verificar si ya has sido mordido por el bug del startup, o si ya has comenzado tu emprendimiento. Tambien es genial si has estado alli por un tiempo, y necesitas volver a la tierra. El libro contiene 474 paginas, pero hay unos 10 puntos del libro que tocaron algo en mi:

  1. La realidad del comienzo. No va a mejorar - ya esta. Las personas iniciadoras son como los monasterios medievales: siempre convencidos que el paraiso esta justo adelante o que las cosas recientemente han empeorado.
  2. La realidad de incrementar el dinero. La analogia del mundo real mas cercana a incrementar ingresos, son las citas rapidas. Es verdad: en 5 minutos, la persona persona decide si esta interesada en vos, como en los bares o bailes. No esta bien, ni es justo, pero es la realidad.
  3. La realidad de planear y ejecutar. Si pensas que incrementar el dinero no es la parte dificil, estas por sorprenderte. El incrementar el dienro, es la parte fácil y divertida. El trabajo real comienza cuando debes entregar los resultados prometidos.
  4. La realidad de la innovación. Muchas personas que la innovación es fácil: te sentás con tus amigos e ideas mágicas ingresan en tu cabeza. O tus clientes te dicen lo que necesitan. Segui soñando. La innovación es dura, es un proceso sucio que no tiene atajos.
  5. La realidad del marketins. Todo el mundo desea hacer las cosas divertidas: relacionarse con personas hermosas, y crear campañas de marketing. Mas precisamente, el marketing es el proceso de convencer a las personas que necesitan tu producto. Eso no es tán fácil, ni divertido.
  6. La realidad de comunicar. El emprendedorismo es una actividad enfocada hacia afuera. Requiere que te comuniques con otros utilizando todas las formas modernas. Cada forma es una habilidad que debes dominar. Todo esto lleva leer este libro y 20 años de práctica.
  7. La realidad de competir. Si no estas compitiendo con otros por un largo tiempo, puede significar que estas intentando satisfacer un mercado que en realidad no existe.
  8. La realidad de tomar y despedir. Estas son artes oscuras para la mayoría de las personas. Pocas personas están entrenadas para cualquiera, y muchos dependen de sus agallas. Piensan que no cometerán errores en la contratación, entonces nunca tendrán que despedir a nadie. Es incorrecto, y los errores lastiman a las personas y a vos.
  9. La realidad del trabajo. Al comienzo, startups (inicios) son como una hoja de papel en blanco: solo oportunidades y en la parte superior una chance de crear significado y cambiar al mundo. Luego la realidad del trabajo comienza. Crear un éxito es difícil, muy difícil realmente.
  10. La realidad de hacer el bien. Al final de nuestras vidas, sos medido no por la cantidad de dinero que has hecho, sino porque tanto has hecho de este mundo un lugar mejor. Los emprendedores exitosos generalmente cambian a emprendimientos sin fines de lucro y sociales para un impacto real.

Conclusión

Ahora vuelvo a mi opinión y el porque decidí levantar la información de otro post. Me pareció muy bien explicados muchos puntos que todas las personas que hemos comenzado algún emprendimiento, nos hemos enfrentado. Creo que explica bastante bien las diferencias que son ver las cosas de afuera, al verlas desde adentro. Muchas veces cuando uno es joven y no tiene demasiada experiencia, puede cometer el error de querer comenzar un emprendimiento pensando que es todo muy fácil, y luego tener que enfrentarse a la realidad que a veces puede ser muy buena, pero otras puede ser un poco adversa. El emprender es una muy linda experiencia, pero también desgastante por eso debemos estar preparados.

Para finalizar, deseo agregar una frase de Confucio: "Escucho y olvido, veo y recuerdo, hago y aprendo".

6 sept 2009

Nuevo emprendimiento MaryKay de Lorena

Lorena esta comenzando un nuevo emprendimiento como Consultora de Belleza Independiente MaryKay, por eso todos aquellos que se quieran interiorizar en los productos MaryKay, los invito a que visiten su nuevo sitio web Brilla con MaryKay.

Muchos éxitos en este nuevo emprendimiento!!!

WebServices con NuSOAP en PHP - Ejemplo 1


Ya hace un tiempo realice un artículo sobre servicios web con PHP (utilizando NuSOAP), el mismo se puede acceder en WebServices con PHP usando NuSOAP, el mismo ya ha quedado un poco obsoleto debido a que el servidor que alojaba el webservice ya no lo contiene más. Por tal motivo y debido a que uno de los inconvenientes principales cuando uno se esta iniciando en el tema de los webservices con PHP, principalmente con NuSOAP, es encontrar como realizar el módulo servidor. En este primer post, decidí subir un ejemplo sencillo de comunicación entre un módulo servidor que provee expone una función, y un módulo cliente que las consume.

Introducción al ejemplo

No voy a exponer demasiados detalles con respecto a que son los WebServices, para ello pueden acceder al enlace que mencione anteriormente (WebServices con PHP usando NuSOAP). Solamente me limitare a explicar un poco el funcionamiento del mismo
Para el ejemplo, estoy utilizando la siguiente estructura de directorios


Siendo, nusoap_server_ej1.php el servidor de nustro WebService con NuSOAP, y nusoap_client_ej1.php el cliente.

Requerimientos

Los requerimientos para poner en funcionamiento el ejemplo son simplemente NuSOAP y tener algún servidor de sitios web (como puede ser Apache) corriendo PHP. Para todos aquellos que actualmente no tienen un servidor corriendo, pueden descargar XAMPP que es un servidor apache con PHP (también trae otras funcionalidades, pero estas 2 son las que importan para nuestro ejemplo) que solo se descarga, se descomprime, y con solo ejecutar un archivo, se inicia el servidor Apache con PHP en nuestra computadora, sin necesidad de mayores dolores de cabeza (Funciona tanto para Windows, como para OS-X).

Módulo servidor

El servidor de este ejemplo es muy sencillo, tan sencillo como el siguiente código:
<?php
 
// Incorporar la biblioteca nusoap al script, incluyendo nusoap.php (ver imagen de estructura de archivos)
require_once('nusoap/lib/nusoap.php');
// Modificar la siguiente linea con la direccion en la cual se aloja este script
$miURL = 'http://pruebas.orlandobrea.com.ar/nusoap_ej1';
$server = new soap_server();
$server->configureWSDL('ws_orlando', $miURL);
$server->wsdl->schemaTargetNamespace=$miURL;


/*
 * Ejemplo 1: getRespuesta es una funcion sencilla que recibe un parametro y retorna el mismo
 * con un string anexado
 */
$server->register('getRespuesta', // Nombre de la funcion
 array('parametro' => 'xsd:string'), // Parametros de entrada
 array('return' => 'xsd:string'), // Parametros de salida
 $miURL);
function getRespuesta($parametro){
 return new soapval('return', 'xsd:string', 'soy servidor y devuelvo: '.$parametro);
}

// Las siguientes 2 lineas las aporto Ariel Navarrete. Gracias Ariel
if ( !isset( $HTTP_RAW_POST_DATA ) )
    $HTTP_RAW_POST_DATA = file_get_contents( 'php://input' );

$server->service($HTTP_RAW_POST_DATA);
?>
El ejemplo es bastante sencillo, simplemente registra una función que recibe un parámetro y devuelve dicho parámetro con un texto adelante ("soy el servidor y devuelvo: ". El parámetro de entrada a la función es del tipo String, y la función también retorna un String.
Anteriormente mencione que no iba a detallar demasiado en código, ya que como pueden ver el mismo esta comentado, y creo que es bastante entendible.
Como podemos ver en el ejemplo, la complejidad mayor en crear el módulo servidor para un webservice, es crear la estructura de datos del mismo y sus tipos (ver $server->register() en el ejemplo). Si bien el ejemplo es muy sencillo, podemos ver que tanto los datos que el webservice recibe, como los que retorna, deben ser especificados en los tipos de datos predefinidos en XML para crear un Schema (xsd:string, xsd:int, etc.). En los próximos ejemplos que vaya subiendo de webservices con NuSOAP se podrá ver más en detalle algunos tipos de datos, y también como crear estructuras complejas (retornar objetos, o listas). Por el momento solo estamos recibiendo un String (xsd:string y retornamos otro entero (xsd:string).
En el ejemplo se puede ver que la función a la cual el webservice llama para atender la petición, en este caso getRespuesta, debe codificar la respuesta en el tipo de datos esperado. En este caso definimos que la función retornaría un xsd:string, por lo que debemos crear un soapval con el tipo de datos esperado.

¿Como se enlazan los datos recibidos por el servidor con nuestra función?

Cuando definimos los parámetros, tanto de entrada, como de respuesta, a los mismos le asignamos un nombre. Por ejemplo al parámetro de entrada le asignamos el nombre "parametro" (si, no es muy original, pero sirve para entender el ejemplo). Y el parámetro de salida, o retorno, lo llamamos "return". Entonces lo que hará NuSOAP es enlazar el parámetro de entrada a la función getRespuesta cuyo nombre es "parametro", con el valor que tome el "parametro" definido en el webservice. Voy a mostrár graficamente el enlace, para que sea más sencilla su visualización:
 

¿Que pasa si mi función NO recibe parámetros?

Simplemente modificariamos el código de:
$server->register('getRespuesta', // Nombre de la funcion
 array('parametro' => 'xsd:string'), // Parametros de entrada
 array('return' => 'xsd:string'), // Parametros de salida
 $miURL);
al siguiente código:
$server->register('getRespuesta', // Nombre de la funcion
 array(), // Parametros de entrada
 array('return' => 'xsd:string'), // Parametros de salida
 $miURL);
y obviamente a la función que hacemo referencia (getRespuesta) no debería recibir parámetros, por lo que pasaría de:
function getRespuesta($parametro){
a:
function getRespuesta(){

El cliente

Para este ejemplo que estoy mostrando, el cliente tiene un poco más de código que el servidor, para ejemplos un poco más complejos, el servidor comienza a ser un poco más largo, y el cliente mantiene apróximadamente la misma longitud. ¿Por que pasa esto? sencillo, a medida que el ejemplo se hace más complejo, se necesitán funciones más complejas en el servidor y principalmente, definir que los datos que vamos a utilizar también son más complejos. Pero eso lo dejaremos para futuros ejemplos que vaya subiendo al blog. Ahora nos concentraremos en el cliente, cuyo código es el siguiente:
<?php
// Incluimos la biblioteca de NuSOAP (la misma que hemos incluido en el servidor, ver la ruta que le especificamos)
require_once('nusoap/lib/nusoap.php');
// Crear un cliente apuntando al script del servidor (Creado con WSDL) - 
// Las proximas 3 lineas son de configuracion, y debemos asignarlas a nuestros parametros
$serverURL = 'http://pruebas.orlandobrea.com.ar';
$serverScript = 'nusoap_server_ej1.php';
$metodoALlamar = 'getRespuesta';

// Crear un cliente de NuSOAP para el WebService
$cliente = new nusoap_client("$serverURL/$serverScript?wsdl", 'wsdl');
// Se pudo conectar?
$error = $cliente->getError();
if ($error) {
 echo '<pre style="color: red">' . $error  . '</pre>';
 echo '<p style="color:red;'>htmlspecialchars($cliente->getDebug(), ENT_QUOTES).'</p>';
 die();
}

// 1. Llamar a la funcion getRespuesta del servidor
$result = $cliente->call(
 "$metodoALlamar", // Funcion a llamar
 array('parametro' => 'Orlando'), // Parametros pasados a la funcion
 "uri:$serverURL/$serverScript", // namespace
 "uri:$serverURL/$serverScript/$metodoALlamar" // SOAPAction
);
// Verificacion que los parametros estan ok, y si lo estan. mostrar rta.
if ($cliente->fault) {
 echo '<b>Error: ';
 print_r($result);
 echo '</b>';
} else {
 $error = $cliente->getError();
 if ($error) {
 echo '<b style="color: red">Error: ' . $error . '</b>';
 } else {
 echo 'Respuesta: '.$result;
 }
}

?>
Primero voy a hacer un breve resumen de cuales son los pasos que se realizan.
  • Incluír la biblioteca de NuSOAP de PHP.
  • Defino las variables de configuración (lo hice de esta forma para que les sea más sencillo el definir los parámetros para sus propios servicios web).
  • Creo el objeto NuSOAP Cliente (nusoap_client).
  • Verifico que la conexión se haya podido realizar.
  • Llamó al servicio web del servidor (función getRespuesta definida en las variables de configuración).
  • Verifico que la llamada haya sido exitosa, en caso de ser exitosa muestro la respuesta del servidor, y en caso de error, muestro el mensaje de error.
El código del cliente también esta comentado, y definí 3 variables al principio que nos permitirán adaptar el cliente del WebService a nuestras pruebas particulares.
En el cliente no hago un procesamiento de la información recibida desde el servidor de WebServices (NuSOAP server) sino que la muestro directamente por pantalla, cuando estemos trabajando realmente con dicha información debemos realizar un procesamiento de la información recibida antes de utilizarla (el procesamiento puede ser desde algo tan sencillo como mostrar la información en un sitio especifico del website, hasta generar tablas o campos de edición). Las posibilidades de procesamiento son infinitas, y dependen de para que estemos utilizando el WebService, y la información otorgada por el mismo.

Verificación de los scripts

Para comprobar que nuestros scripts estan funcionando, lo que primero recomiendo es primero acceder al script del servidor (http://<direccion de nuestro server>/nusoap_server_ej1.php) desde nuestro navegador, el cual nos debe mostrar una pantalla similar a la siguiente si todo esta correcto (en caso contrario mostrará un típico error PHP por pantalla):

Y si hacemos click sobre el nombre la la función que hemos publicado en nuestro servidor de WebService, nos mostrará algo similar a esto:

Cuando hemos verificado que el servidor esta funcionando, ahora realizaremos la prueba del cliente (http://<direccion de nuestro server>/nusoap_client_ej1.php), y nos mostrará una página similar a la siguiente:

Conclusión

El WebService aquí presentado es un ejemplo básico para todas aquellas personas que estan comenzando con ellos y desean utilizar NuSOAP para crear los mismos y consumirlos.  El código del ejemplo es muy sencillo, pero igualmente decidí publicar un archivo con el ejemplo del cilente y el servidor, para que sea más sencilla la implementación del ejemplo en sus computadoras (Descargar el ejemplo).

5 sept 2009

Ver color hexadecimal HTML

 
Valor hexadecimal del color a ver:

3 sept 2009

Problema con Mail de Apple Templates y Adjuntos

Luego de publicar el post de como crear templates para mail de apple y de un de trabajar con el mismo, me dí cuenta que no permite adjuntar archivos que no sean de imagen. Es decir, cuando estamos utilizando un template para la creación de nuestro e-mail, no podemos agregar archivos adjuntos al mismo (en realidad solo podemos agregar archivos adjuntos de imagen).

Este inconveniente se me presentó al intentar enviar un e-mail a un cliente, al cual le debia adjuntar un archivo, ahí el Mail de Apple me mostró este hermoso mensaje.

Por el momento no he encontrado solución para este inconveniente, aunque sinceramente no he investigado demasiado aún. Espero poder encontrar alguna alternativa para poder seguir utilizando templates, y poder adjuntar archivos.

2 sept 2009

Crear templates para Mail de Apple

Introducción

Una función que para mí es bastante importante en los clientes de e-mail es poder tener la posibilidad de realizar plantillas para nuestros mensajes. Esto nos permite dar un formato más complejo a nuestros e-mails, y que los mismos sean homogéneos. Tener la posibilidad de realizar templates se hace aún más importante en el ámbito laboral, en el cual muchas veces con solo una firma no es suficiente para los e-mails que enviamos.

En esta oportunidad voy a detallar como podemos crear plantillas de e-mail para la aplicación Mail de Apple (OS X).

Los pasos


Crear un template

El primer paso para poder crear un template es comenzar con uno vacio, para ello podes descargar mi template vacio y comenzar a trabajar con el (una vez que lo descarguemos debemos descomprimir el archivo, obtienendo de esta forma un archivo con nombre "obrea Basico.mailstationery").

Abrir el template

Para abrir el template solo debemos hacer CTRL-Click sobre el mismo (o botón derecho del mouse) y seleccionar la opción "Mostrar contenido del paquete"

Se abrirá el Finder dentro del contenido del archivo (los archivos mailstationary en realidad es un paquete con varios archivos dentro). Accedemos a la carpeta "Contents/Resources".

Editar el template

Con el editor de html que estemos acostumbrados a utilizar (yo utilizo Smultron) abrimos el archivo "content.html" el cual tiene un contenido similar a este:

<html>
<head>
        <title>Template creado obrea.blogspot.com</title>
</head>
<body style="margin: 0 0 0 10px;"> 
    
<div style="background-color: #fff; margin: 10px; padding: 10px;">
<div id="encabezado">
  <img src="obreaFondo.jpg" />
</div>

<br/>
<div id="mail-to" contenteditable="true" apple-content-name="to">Reemplazar por un saludo tipico,</div>
<br/>
<div id="mail-body"contenteditable="true" apple-content-name="body">
Reemplazar por un texto predeterminado
</div>
<p contenteditable="true" apple-content-name="bye">Reemplazar por un saludo final tipico,</p>


<div id="pie">
-----------<br/>
Reemplazar por mi nomrbre<br/>
Reemplazar por otros datos que quiera agregar al pie<br/>
</div>
</div>

</body>
</html>

Como podemos ver en el código es todo html puro, por lo tanto es muy fácil poder llevar un diseño que ya tenemos en HTML a un template para Mail de Apple.

Si viste el c&ooacute;digo en profundidad podrás ver que existen algunas propiedades en los tags que no son standares:

 
contenteditable="true"

apple-content-name="un_nombre"

Igualmente sus nombres describen bastante bien cual es su funcionalidad. el código contenteditable="true" le indica a la aplicación Mail que lo que se encuentra envuelto por el tag contenedor puede ser editado. Un punto importante a tener en cuenta, que no mencione anteriormente, es que todo aquello que no se indique explicitamente que puede ser modificado, queda fijo en el template (es decir, todo lo que no indica contenteditable="true" queda fijo como si fuera constante y no puede ser modificado cuando estamos editando el email).

La otra propiedad tiene menos importancia y realmente no es necesaria, pero igualmente la describiré. La propiedad apple-content-name indica el nombre con el cual la aplicación Mail de Apple identifica al contenido del tag. No es indispensable agregarla

En el código de ejemplo, existen 3 áreas editables:

Parte 1

<div id="mail-to" contenteditable="true" apple-content-name="to">Reemplazar por un saludo tipico,</div>

En esta secció podemos ingresar el saludo que tipicamente utilizamos con nuestros destinatarios de e-mail. Por ejemplo: "Hola ," para luego solo tener que ingresar el nombre entre "Hola" y ",".

Parte 2

<div id="mail-body"contenteditable="true" apple-content-name="body">
Reemplazar por un texto predeterminado
</div>

Si tenemos algún tipo de formato de texto que utilicemos siempre en nuestros e=mails, por ejemplo una introducción común podemos agregarlo en esta sección para no tener que escribirla por cada mensaje que enviamos

Parte 3

<p contenteditable="true" apple-content-name="bye">Reemplazar por un saludo final tipico,</p>

En esta última parte podemos indicar cual es el saludo que habitualmente utilizamos. Por ejemplo: "Saludos", "Un abrazo" o cualquier otro texto que utilicemos habitualmente.

Seguimos?

En el template que esta en el sitio, es muy básico, pero sirve para tener una idea de las opciones que nos da esta aplicación. En otro post indicaré como se puede reemplazar una imagen del template con solo hacer un drag and drop sobre la misma, cuando estamos editando el e-mail.

Recomiendo que al momento de estar editando el template, tengamos abierto el archivo content.html en un navegador, por ejemplo Safari, para poder ir viendo como quedan los cambios que vamos realizando

Cada vez que utilicemos una imagen en el template, y la misma no se ecuentre en un sitio web (es decir que se debe env&iactute;r con el e-mail), debemos copiarla en la misma carpeta en la cual se encuentra el archivo content.html (un ejemplo de ello es el archivo obreaFondo.jpg que contiene el banner superior del e-mail).

Una vez que adaptes el template a como más te guste, con tu logo, firma, y todo aquello que quieras agregar, estas en condiciones de seguir con el siguiente paso

Editamos Description.plist

En este archivo debemos ingresar el nombre de todos los archivos de imagen que hemos utilizado en nuestro template. A continuación copio el archivo del template básico:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Folder Name</key>
    <string>obrea Basico.mailstationery</string>
    <key>HTML File</key>
    <string>content.html</string>
    <key>Images</key>
    <array>
        <string>obreaFondo.jpg</string>
    </array>
    <key>Stationery ID</key>
    <string>52CF436E-68DA-4842-B638-1234567</string>
</dict>
</plist>

En este archivo debemos prestar atención a dos secciones, la primera:


    <string>obrea Basico.mailstationery</string>

Que indica cual es el nombre de nuestro archivo de templates, lo debemos modificar por el nombre que le vayamos a poner al archivo contenedor

La segunda sección a la cual debemos prestar atención es


    <key>Images</key>
    <array>
        <string>obreaFondo.jpg</string>
    </array>

Que indica cuales son las imagenes que estamos utilizando en nuestro template, debemos agregar un <string> </string> por cada archivo de imagen que utilicemos en el template. En este caso estamos utilizando solo uno obreFondo.jpg

Asignamos el nombre que se mostrará en Mail

Para ello abrimos el archivo "DisplayName.strings" que se encuentra en la carpeta "English.lproj" y vamos a la línea


"Display Name" = "Template basico";

En esta línea modificamos "Template basico" por el nombre con el cual queremos que aparezca identificado nuestro template dentro de la aplicación Mail

Copiamos el paquete modificado

Una vez que realizamos los pasos anteriores, estamos en condiciones de poder guardar ya nuestro template para comenzar a utilizarlo. Para ello cerramos la ventana del Finder que esta mostrando el contenido del paquete que abrimos (este paso no es necesario, pero es mejor realizarlo para no confundirnos con los archivos).

Vamos al directorio en el cual se encuentra el template que modificamos (el paquete con el template), y modificamos el nombre del mismo por el que hayamos ingresado en Description.plist.

Abrimos una nueva ventana del Finder y accedemos al siguiente directorio "/Library/Application Support/Apple/Mail/Stationery/Apple/Contents/Resources/" luego seleccionamos una carpeta en la cual deseamos incorporar nuestro template, en el ejemplo voy a elegir la carpeta "Announcements", dentro de dicha carpeta accedemos a "Contents/Resources" y dentro de dicho directorio copiamos el archivo que hemos generado a esta carpeta.

Usando el template

Ya estamos en condiciones de poder utilizar el template. Para ello solo debemos crear un nuevo e-mail.

Luego seleccionamos "Mostrar plantillas".

Seleccionamos la categoría que le asignamos al template que hemos realizado.

Seleccionamos el template que generamos (aparecerá el nombre que le hayamos asignado en "Display Name" del archivo "DisplayName.strings").

Aparecerá el template en el cuerpo del mensaje que estamos creando, permitiendonos editar en todas aquellas secciones que hayamos habilitado.

Conclusión

Si bien son varios pasos, es bastante sencilla la modificaci&acue;n y creación de templates para la aplicación Apple Mail.

Hasta el momento es la aplicación de e-mail que mejor integración con templates he encontrado, ya que Outlook, o Mozilla, tienen una buena integración, pero no nos permite con un solo drag and drop cambiar una imagen, o modificar solo partes del template (muy util para no equivocarnos y perder la estética general por borrar una parte que no queriamos)

Te recomiento probar los templates del Mail de Apple, y en caso que aún no hayas probado el Mail de Apple, te propongo que lo hagas, para que puedas ver si también se adapta a tus necesidades