|
||||
|
||||
Usando servicios web$xmlhttp_request es una manera de saber si vamos a aceptar peticiones por AJAX. Esto se puede saber gracias a que si la petición se realiza por AJAX, $_SERVER["HTTP_X_REQUESTED_WITH"] tiene el valor literal "XMLHttpRequest", con lo que ya podemos saber si viene o no por AJAX. $post_request, $get_request y $browser_request sirven para lo mismo, repectivamente, para peticiones GET, POST y por navegador. El argumento $require_query especifica al servicio si se requiere una lista de argumentos para poder acceder a el. El último argumento, $arg_list, es un array de nombres de variables que queremos que compruebe contra las variables que nos estén llegando. Así, por dentro, analiza de donde le viene la petición, si el numero de argumentos que vienen son correctos, y termina su ejecución en caso de haber algún error. Luego veremos por qué es esto. Recomiendo leer tanto el código de la clase como el fichero de PHPDocumentor que hay junto con el código fuente. Solo así veréis que hace la clase base, no la pongo aquí por ser un poco larga. Ahora veamos el código de una clase que hereda de esta, está en el fichero phpAjax/BasicTestService.class.php
phpAjax/BasicTestSrvice.class.php <?php require_once(realpath("JSONWebServiceBase.class.php")); class BasicTestService extends JSONWebServiceBase { public function __construct($xmlhttp_request = REQUEST_ACCEPT, $post_request = REQUEST_ACCEPT, $get_request = REQUEST_ACCEPT, $browser_request = REQUEST_ACCEPT, $require_query = false, $arg_list = null) { parent::__construct($xmlhttp_request, $post_request, $get_request, $browser_request, $require_query, $arg_list); if($this->_accessMethod["who"] == WHO_BROWSER) { echo "Todo correcto, este es el objeto: <br/>"; $this->toString(); } else { $this->_jsonArray["CODE"] = "OK"; $this->dieJSON(); } } } $service = new BasicTestService(); ?> Esta clase es muy simple, lo único que hace es emplear toda la funcionalidad de la que hereda para mostrar que el servicio está activo. Permite todos los modos de acceso, dado que en el constructor tiene especificados por defecto todos los argumentos. En caso de ser llamado por navegador, por GET o POST, hará un print_r del objeto para mostrar que ha heredado de la clase madre, y que existe. En caso de ser llamado por AJAX, devuelve un array de JSON, en el que el elemento CODE contiene el texto "OK". El método processData() está vacio en la clase base, de tal forma que la idea es reescribir este método y llamarlo para realizar la funcionalidad. El porque de que la clase base no haga nada mas que instanciarse, cargar los argumentos, y comprobar la seguridad, es que como lo primero que las clases derivadas van a hacer es llamar a parent::__construct(), es decir, al constructor de la clase base, no tiene sentido continuar realizando operaciones si las condiciones de acceso al servicio que hemos establecido no son las adecuadas.
Este código es muy bonito, pero no sirve, de momento, para nada. Lo útil que tiene es que podemos saber como viene la petición y qué hacer al respecto. Vamos a ver un ejemplo de servicio que en función de por donde venga la petición (GET ó POST) y si es por AJAX o navegador, y en función de los argumentos, realizará una operación o la otra. El propósito último de la clase es sumar dos números enteros. Su código es como sigue:
phpAjax/IntegerAddService.class.php <?php require_once(realpath("JSONWebServiceBase.class.php")); class IntegerAddService extends JSONWebServiceBase { public function __construct($xmlhttp = REQUEST_ACCEPT, $post = REQUEST_ACCEPT, $get = REQUEST_ACCEPT, $browser = REQUEST_ACCEPT, $require_query = false, $arg_list = null) { parent::__construct($xmlhttp, $post, $get, $browser, $require_query, $arg_list); switch($this->_accessMethod["who"]) { case WHO_BROWSER: if($this->_accessMethod["how"] == HOW_GET && empty($this->_requestData)) { echo "<form method='POST' action='IntegerAddService.class.php'>"; echo "<input type='text' name='num1'> + <input type='text' name='num2'>"; echo "<input type='submit' value='Suma'>"; echo "</form>"; } else { if(!empty($this->_requestData) && array_key_exists("num1", $this->_requestData) && array_key_exists("num2", $this->_requestData)) { echo "Resultado: ".($this->_requestData["num1"] + $this->_requestData["num2"]); } else { die("El acceso sin parámetros o con parámetros erróneos no es correcto"); } } break; case WHO_AJAX: if(!empty($this->_requestData) && array_key_exists("num1", $this->_requestData) && array_key_exists("num2", $this->_requestData)) { $this->_jsonArray["CODE"] = "OK"; $this->_jsonArray["RESULT"] = $this->_requestData["num1"] + $this->_requestData["num2"]; } else { $this->_jsonArray["CODE"] = "ERROR"; $this->_jsonArray["EXPLAIN"] = "AJAX sin parámetros o con parámetros erróneos no es accesible"; } break; } } } $sumador = new IntegerAddService(); ?> El código es un poco largo porque quería explicar todo lo que se puede hacer en este caso. Inicializamos el servicio de un modo totalmente permisivo, y empezamos a comprobar de donde viene la petición. Si es por GET y viene sin argumentos, mostramos un formulario para que inserte los numeros a sumar, cuya action es el propio servicio. Si entramos por GET o POST con dos argumentos num1 y num2, nos devuelve el resultado por pantalla. Es aquí donde, siendo mas trabajadores, haríamos el envío de XML o SOAP en caso de que quisiésemos que nuestro servicio hiciese eso. Si venimos por AJAX, obligamos a que nos vengan dos parámetros num1 y num2. Si alguien se está preguntando de donde salen los parámetros o como acaban en $this->_requestData, que se lea la clase base, ahí viene todo el código de recogida de parámetros. Así que ya tenemos un servicio que admite diferentes peticiones de diferentes fuentes y que responde de una u otra forma en función de lo que le digamos. El código para testear el servicio está en el fichero integer_add_test.php de los ficheros del tutorial. En el podréis ver como realizo diferentes llamadas AJAX, POST y GET al servicio y lo que devuelven en cada caso. Alguien se podría preguntar porque no he usado $require_query y $arg_list para asegurar los parámetros num1 y num2. Es para poder mostrar el formulario en caso de llegar de esta forma. Se podría eliminar esa parte del código y solo permitir el acceso a través de los argumentos dados. Pongo el ejemplo de como sería esa clase, con un código bastante mas corto, para que se entienda lo que quiero decir.
phpAjax/IntegerAddServiceRequired.class.php <?php require_once(realpath("JSONWebServiceBase.class.php")); class IntegerAddServiceRequired extends JSONWebServiceBase { public function __construct($xmlhttp, $post, $get, $browser, $require_query, $arg_list) { parent::__construct($xmlhttp, $post, $get, $browser, $require_query, $arg_list); switch($this->_accessMethod["who"]) { case WHO_BROWSER: echo "Resultado: ".($this->_requestData["num1"] + $this->_requestData["num2"]); break; case WHO_AJAX: $this->_jsonArray["CODE"] = "ERROR"; $this->_jsonArray["EXPLAIN"] = "AJAX sin parámetros o con parámetros erróneos no es accesible"; break; } } } $sumador = new IntegerAddServiceRequired(REQUEST_ACCEPT,REQUEST_ACCEPT,REQUEST_ACCEPT,REQUEST_ACCEPT,true,array("num1","num2")); ?> La diferencia mas importante entre una clase y la otra es que esta segunda ya está aprovechando toda la funcionalidad heredada de la clase base para dar por hecho que recibe dos argumentos, num1 y num2. En caso de no recibirlos, es la clase base la que se encarga de no instanciarse, y de devolver un mensaje de error en texto plano (si el acceso se hizo por navegador), o devolver un array de JSON con una descripción del error para poder mostrarlo con javascript. Esto es todo por ahora, en el siguiente capítulo veremos como hacer un comprobador de cajas de texto a través de AJAX, que en base a unas reglas nos dirá si la entrada es correcta o no, en tiempo real.
|
||||
|
||||