Archive for the 'Infinitos monos aporreando infinitos teclados' Category

Objetos maestros en PHP

Ya comenté el tema de usar clases “principales” para un proyecto… y ahora vuelvo con el mismo tema. Muy creativo, sí…

La idea es la de tener un objeto principal (maestro) con un constructor que crea dentro del propio objeto tantos objetos “internos” como hagan falta, pasándole por referencia su propio objeto al constuctor de los “objetos internos”.

Los “objetos internos” extienden a una plantilla de objeto, y esa plantilla contiene un constructor que a su vez “guarda” como referencia el parámetro pasado por el objeto principal.

Sí, es un lío, así que mejor verlo en código:

class AppObjectSkel {
  function __construct(&$parent) {
    $this->_parent = $parent;
    if(is_callable(array($this, 'init'))) $this->init();
  }
}

class AppDatabase extends AppObjectSkel {
  function init() {
    /* Aquí se inicializa la DB */
  }
}

class AppCache extends AppObjectSkel {
  /* Elemento de cache, no lo inicializamos en este ejemplo */
}

class Application {
  function __construct() {
    $this->database = new AppDatabase($this);
    $this->cache = new AppCache($this);
  }
}

De esta manera se puede acceder de un elemento a otro. Por ejemplo, desde AppCache se puede acceder a AppDatabase pasando por Application, simplemente usando $this->_parent->database. Al tratarse de un valor pasado por referencia, se puede acceder desde AppDatabase a AppCache y reflejar cambios en tiempo real.

Pero hay que tener en cuenta un pequeño detalle: los constructores. Debido a que se hereda de una clase maestra (AppObjectSkel), no se puede poner constructor de ningún tipo (ya sea __constructor o una función con el nombre de la clase), ya que PHP ejecutará únicamente el del objeto creado (AppCache, por ejemplo) y no el de AppObjectSkel (y mucho menos va a ejecutar dos constructores). Se puede evitar esto de varias formas: evitando AppObjectSkel en todos los casos y copiando el construct a cada vez, copiando el construct sólo cuando lo necesitamos (por que pisamos el construct de AppObjectSkel) o simplemente usar una función opcional (llamada init), como pongo en el ejemplo, que sólo se ejecuta si existe y se llama desde AppObjectSkel, a modo de constructor (un constructor invoca a otro).

Desde la propia aplicación simplemente hay que crear una nueva instancia del objeto Application ($app = new Application) y acceder a los diferentes objetos a partir del maestro ($app->db, $app->cache).

Esto llega a ser muy útil cuando la aplicación entera está divida en objetos (AppUsers, AppForums, AppProfiles...) y es necesario hacer transacciones entre los objetos. En lugar de crear una instancia para cada objeto cada vez que se necesitan (por ejemplo, instanciar AppCache desde AppUsers cuando hace falta usar memcache), se pueden instanciar una sola vez y acceder en un entorno protegido (Application, que vendría a ser un “contenedor” relativamente protegido de variables pisadas y globales erradas), a todos los objetos o variables que haga falta.

Con esto después se pueden hacer montones de cambios (instanciar una clase poco usada sólo cuando se necesita, hacer una especie de namespace para tener un cache durante la ejecución del programa…). Y es que ahí, la imaginación es el límite.

YQL o la gran base de datos que es Internet

Leyendo korben.info (un blog en francés) me he encontrado un post la mar de interesante sobre YQL.

YQL es "Yahoo! Query Language" y es básicamente un sistema de "queries"estructuradas que permite lanzar "consultas" contra Interner entero.

Esto se hace usando una estructura XML pura que es consultada mediante consultas YQL (pseudo-SQL) que pasan antes por Yahoo!, por ejemplo: (hay mejores ejemplos por ahí, merece la pena echar un vistazo)

SELECT * FROM twitter.user.status WHERE id=’adrinavarro’

SELECT * FROM search.web WHERE query=’vacaciones’

SELECT * FROM lastfm.tag WHERE tag=’beck’ AND api_key=’?’

La idea es muy sencilla y a más de uno le va a gustar. Hay una recopilación de las tablas en datatables.org. Para quién le interese probar, existe una consola de pruebas para ejecutar consultas y analizar el resultado.

Para más información, docs sobre YQL y ejemplos (en francés).

A muerte con el mapa

Soy una leyenda. Me refiero a que posiblemente sea la persona más torpe a la hora de desplazarse que puede haber a este lado de tierra. Ni con el GPS del iPhone (sí, tengo un iPhone desde hace poco), ni con las indicaciones de Google Maps. Ni siquiera con las indicaciones por las que voy mendigando…

Vale, odio los mapas. Y soy una verdadera mierda a la hora de situarme, tengo el don de liarla siempre. Mi madre me lo dice, ’sólo tú puedes hacerlo hijo’. No se equivoca. ¿Debería sentirme orgulloso o preocuparme por ello, doctor?

Pero no es mi vida de lo que vengo a hablar, por quién me habéis tomado… Es que he vuelto a enfadarme con Google Maps. Bueno, ahora mismo no, pero sí hace unos meses y ahora que he retomado un poco el jugueteo con el API de Google Maps, es como tomarse mal una CocaCola. Vuelve y jode mucho.

Al turrón. Desde hace relativamente poco (bueno, ya hace bastante que está implementado) se puede usar el API de reverse geocoding desde JavaScript. Es sencillo: creas un nuevo objeto en plan geocoder = new GClientGeocoder(); y llamas a la función getLocations del mismo objeto.

Por dar un ejemplo:

geocoder = new GClientGeocoder();
geocoder.getLocations(latlng, function(addresses) {
if(addresses.Status.code != 200) {
alert("Ubicación no reconocida");
} else {
if(typeof(addresses.Placemark[0].AddressDetails.Country.
\
AdministrativeArea.SubAdministrativeArea.Locality.PostalCode) == "undefined") {
alert("No hemos podido obtener el código postal de este área, con lo que es posible que los resultados de tus búsquedas sean inexactos");
} else {
cp = addresses.Placemark[0].AddressDetails.Country. \

AdministrativeArea.SubAdministrativeArea.Locality.PostalCode. \
PostalCodeNumber;
};
};
);

(Nota mental: vaya pesadilla poner código en WordPress… Donde hay un \ hay que volver a juntar el código (quitando espacios, claro))

Todo este código asume que ya tienes un objeto llamado “latlng” que contiene las coordenadas de Latitud y Longitud que quieres convertir a código postal en este caso. Crear el objeto LatLng es muy fácil: latlng = new GLatLng(latitud, longitud);.

Aunque así parezca fácil, obtener la información reversa no es nada fácil, entre otras por que cambia el resultado si estás haciendo un reverse de un lugar en España, Alemania, Francia o Estados Unidos (jerarquía e informaciones algo diferentes). Por aquí hay un ejemplo básico de qué resultados da el Reverse Geocoding en XML.

Desde JavaScript, es algo así: del objeto se saca un array, matriz, tupla, quillostoquéeh de ‘PlaceMark’. Aquí asumimos el primero que es teóricamente el más preciso si no es el único. Dentro tenemos “AddressDetails”. Dentro de esto, “Country”. Dentro de “Country”, llega “AdministrativeArea”. Dentro “SubAdministrativeArea”. Dentro, “PostalCode”. Y ahí, finalmente, “PostalCodeNumber”.

Pese a que todo esto es y parece una pesadilla, obtener la dirección sin más se puede conseguir de una forma un poco más sencilla: addresses.Placemark[0].address;

Y repitiéndome de otras veces, esto no deja de ser una chuleta. Tamaño XL, pero sí… lo es.

Voy a ver si me pongo a hacer una aplicación sencillita para el iPhone, con el API de 11870. Mi idea era simplemente rellenar una “posición actual” con texto libre, pasarlo a coordenadas y pasarlo a reverso para confirmar en limpio (por código postal y dirección) la inserción realizada. Una vez ahí, un formulario de búsqueda libre que simplemente deje buscar a una distancia de nuestra posición actual (el API de 11870 permite búsquedas geográficas, la verdad es que mola un montón).

Voy a ver si no me pierdo demasiado (y de nuevo) con el GeoCoding. No es lugar para desorientados.

(Nota de pie: Sí, estoy copiando un poco –mucho– a Gafeman y su Comil.us, que por cierto, funciona genial y está muy bien –si no lo has hecho, échale un ojo–… pero le tengo ganas al API de Google Maps y a la de 11870, sólo sea por programar un poco para la plataforma webapp-móvil y exprimir al máximo el API JavaScript de Google Maps sin usar los propios mapas).