Subversion Repositories Applications.framework

Compare Revisions

Ignore whitespace Rev 359 → Rev 360

/trunk/framework/RestServeur.php
29,13 → 29,13
* Encodage en sortie : utf8
*
* @category Php 5.2
* @package Framework
* @package Framework
* @author Jean-Pascal MILCENT <jpm@tela-botanica.org>
* @copyright Copyright (c) 2010, Tela Botanica (accueil@tela-botanica.org)
* @license GPL v3 <http://www.gnu.org/licenses/gpl.txt>
* @license CECILL v2 <http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt>
* @license GPL v3 <http://www.gnu.org/licenses/gpl.txt>
* @license CECILL v2 <http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt>
* @since 0.3
* @version $Id: RestServeur.php 344 2011-06-10 07:51:56Z jpm $
* @version $Id: RestServeur.php 359 2011-08-30 13:53:45Z delphine $
* @link /doc/framework/
*/
// TODO : gerer les retours : dans ce controleur : code retour et envoi ...
95,6 → 95,12
* L'utiliser quand le serveur ou un service soulève une erreur ou une exception. */
const HTTP_CODE_ERREUR = '500';
/** Motif de l'epression régulière vérfiant la version de l'API. */
const MOTIF_API_VERSION = '/^[0-9]+(?:[.][0-9]+)*$/';
/** Motif de l'epression régulière vérfiant le nom du service. */
const MOTIF_SERVICE_NOM = '/^[a-z0-9]+(?:[-][a-z0-9]+)*$/';
/** Mettre à true pour activer l'affichage des messages d'erreurs et de débogage.
* @var boolean */
private static $debogageActivation = false;
143,6 → 149,11
* @var array
*/
private static $config = array();
 
/** Tableau contenant les messages d'erreur et/ou d'avertissement du Serveur.
* @var array
* */
private static $messages = array();
/** Codes HTTP. */
private static $http10 = array(
176,6 → 187,7
$this->initialiserRequeteDonnees();
$urlParts = $this->decouperUrlChemin();
$this->initialiserApiVersion(array_shift($urlParts));
$this->initialiserServiceNom(array_shift($urlParts));
$this->initialiserRessource($urlParts);
184,8 → 196,9
// Enregistrement en première position des autoload de la méthode gérant les classes des services
spl_autoload_register(array(get_class(), 'chargerClasse'));
} else {
self::envoyerEnteteStatutHttp(self::HTTP_CODE_ERREUR);
$e = "La classe Serveur du TBFRamework nécessite, pour fonctionner, l'accès aux variables serveurs REQUEST_URI, REQUEST_METHOD et QUERY_STRING.";
trigger_error($e, E_USER_ERROR);
self::ajouterMessage($e);
}
}
210,7 → 223,7
private function decouperUrlChemin() {
if (isset($_SERVER['REDIRECT_URL']) && $_SERVER['REDIRECT_URL'] != '') {
if (isset($_SERVER['REDIRECT_QUERY_STRING'])) {
if (isset($_SERVER['REDIRECT_QUERY_STRING']) && !empty($_SERVER['REDIRECT_QUERY_STRING'])) {
$url = $_SERVER['REDIRECT_URL'].'?'.$_SERVER['REDIRECT_QUERY_STRING'];
} else {
$url = $_SERVER['REDIRECT_URL'];
218,13 → 231,13
} else {
$url = $_SERVER['REQUEST_URI'];
}
//echo '<pre>'; print_r($_SERVER); echo '</pre>';
if (strlen($_SERVER['QUERY_STRING']) == 0) {
$tailleURL = strlen($url);
} else {
$tailleURL = -(strlen($_SERVER['QUERY_STRING']) + 1);
}
//echo '<br/>url : '.$url;
$urlChaine = '';
if (strpos($url, Config::get('serveur.baseURL')) !== false) {
$urlChaine = substr($url, strlen(Config::get('serveur.baseURL')), $tailleURL);
235,24 → 248,48
}
private function initialiserApiVersion($apiVersion) {
if (isset($apiVersion) && !empty($apiVersion)) {
if ($this->verifierApiVersion($apiVersion)) {
$this->apiVersion = $apiVersion;
self::$config['chemins']['api'] = Config::get('chemin_modules').$this->apiVersion.DS;
} else {
$e = "Aucune version d'API n'a été spécifié dans l'url qui doit avoir la forme suivante http://www.mondomaine.org/services/apiVersion/monService/";
trigger_error($e, E_USER_ERROR);
self::envoyerEnteteStatutHttp(self::HTTP_CODE_MAUVAISE_REQUETE);
$e = "Aucune version d'API n'a été spécifiée.\n".
"La version doit respecter l'expression régulière suivante : ".self::MOTIF_API_VERSION.".\n".
"L'url doit avoir la forme suivante : http://www.mondomaine.org/services/apiVersion/monService/";
self::ajouterMessage($e);
self::cloreAccesServeur();
}
}
private function verifierApiVersion($apiVersion) {
$apiOk = false;
if (isset($apiVersion) && !empty($apiVersion) && preg_match(self::MOTIF_API_VERSION, $apiVersion)) {
$apiOk = true;
}
return $apiOk;
}
private function initialiserServiceNom($serviceNom) {
if (isset($serviceNom) && !empty($serviceNom)) {
if ($this->verifierServiceNom($serviceNom)) {
$this->service = $this->traiterNomService($serviceNom);
} else {
$e = "Aucun service n'a été spécifié dans l'url qui doit avoir la forme suivante http://www.mondomaine.org/services/apiVersion/monService/";
trigger_error($e, E_USER_ERROR);
self::envoyerEnteteStatutHttp(self::HTTP_CODE_MAUVAISE_REQUETE);
$e = "Aucune nom de service n'a été spécifié.\n".
"La nom du service doit respecter l'expression régulière suivante : ".self::MOTIF_SERVICE_NOM.".\n".
"L'url doit avoir la forme suivante : http://www.mondomaine.org/services/apiVersion/monService/";
self::ajouterMessage($e);
self::cloreAccesServeur();
}
}
private function verifierServiceNom($serviceNom) {
$serviceNomOk = false;
if (isset($serviceNom) && !empty($serviceNom) && preg_match(self::MOTIF_SERVICE_NOM, $serviceNom)) {
$serviceNomOk = true;
}
return $serviceNomOk;
}
private function traiterNomService($serviceNom) {
return str_replace(' ', '', ucwords(str_replace('-', ' ', strtolower($serviceNom))));
}
294,20 → 331,28
if (class_exists($classe)) {
return null;
}
 
$classeTrouvee = false;
$chemins = array('', self::$config['chemins']['api']);
foreach ($chemins as $chemin) {
$chemin = $chemin.$classe.'.php';
if (file_exists($chemin)) {
require_once $chemin;
$classeTrouvee = true;
}
}
if ($classeTrouvee === false) {
self::envoyerEnteteStatutHttp(self::HTTP_CODE_RESSOURCE_INTROUVABLE);
$e = "La classe '$classe' du service n'a pas été trouvée par le serveur.\n".
"Cela peut signifier que le nom du service saisi comporte une erreur.";
self::ajouterMessage($e);
self::cloreAccesServeur();
}
}
/**
* Execute la requête.
*/
function executer() {
public function executer() {
switch ($this->methode) {
case 'GET':
$this->get();
322,11 → 367,13
$this->put();
break;
default :
$e = "La méthode HTTP '{$this->methode}' n'est pas prise en compte par ce serveur REST.";
trigger_error($e, E_USER_WARNING);
self::envoyerEnteteStatutHttp(self::HTTP_CODE_METHODE_NON_AUTORISE);
header('Allow: GET, POST, DELETE, PUT');
$e = "La méthode HTTP '{$this->methode}' n'est pas prise en compte par ce serveur REST.\n".
"Consulter l'entête Allow pour connaître les méthodes autorisées.";
self::ajouterMessage($e);
}
// Affichage des exceptions et erreurs générées par les services
$this->gererErreurs();
$this->cloreAccesServeur();
}
 
/**
341,9 → 388,10
$methodeGet = self::METHODE_GET;
$Service->$methodeGet($this->ressources, $this->parametres);
} else {
self::envoyerEnteteStatutHttp(self::HTTP_CODE_RESSOURCE_INTROUVABLE);
$e = "Le service '{$this->service}' ne contient pas la méthode '".self::METHODE_GET."' nécessaire ".
"lors de l'appel du service via la méthode HTTP GET.";
trigger_error($e, E_USER_ERROR);
self::ajouterMessage($e);
}
}
}
350,7 → 398,6
 
private function post() {
$paires = $this->parserDonneesRequete();
 
if (count($paires) != 0) {
if (isset($paires['action']) && $paires['action'] == 'DELETE') {// Altnative à l'utilisation de DELETE
$this->delete();
361,40 → 408,48
$Service = new $this->service(self::$config);
if (method_exists($Service, self::METHODE_POST)) {
$methodePost = self::METHODE_POST;
if ($Service->$methodePost($this->ressources, $paires)) {
$info = $Service->$methodePost($this->ressources, $paires);
if ($info === true) {
$this->envoyerEnteteStatutHttp(self::HTTP_CODE_CREATION_OK);
}
} else {
self::envoyerEnteteStatutHttp(self::HTTP_CODE_RESSOURCE_INTROUVABLE);
$e = "Le service '{$this->service}' ne contient pas la méthode '".self::METHODE_POST."' nécessaire ".
"lors de l'appel du service via la méthode HTTP POST.";
trigger_error($e, E_USER_ERROR);
"lors de l'appel du service via la méthode HTTP GET.";
self::ajouterMessage($e);
}
}
}
} else {
$this->envoyerEnteteStatutHttp(self::HTTP_CODE_CONTENU_REQUIS);
$e = "Le service '{$this->service}' requiert de fournir le contenu à modifier dans le corps ".
"de la requête avec la méthode HTTP POST.";
self::ajouterMessage($e);
}
}
 
private function put() {
$paires = $this->parserDonneesRequete();
 
if (count($paires) != 0) {
if ($this->service != null) {
$Service = new $this->service(self::$config);
if (method_exists($Service, self::METHODE_PUT)) {
$methodePut = self::METHODE_PUT;
if ($Service->$methodePut($this->ressources, $paires)) {
$info = $Service->$methodePut($this->ressources, $paires);
if ($info === true) {
$this->envoyerEnteteStatutHttp(self::HTTP_CODE_CREATION_OK);
}
} else {
self::envoyerEnteteStatutHttp(self::HTTP_CODE_RESSOURCE_INTROUVABLE);
$e = "Le service '{$this->service}' ne contient pas la méthode '".self::METHODE_PUT."' nécessaire ".
"lors de l'appel du service via la méthode HTTP PUT (ou équivalant).";
trigger_error($e, E_USER_ERROR);
"lors de l'appel du service via la méthode HTTP GET.";
self::ajouterMessage($e);
}
}
} else {
$this->envoyerEnteteStatutHttp(self::HTTP_CODE_CONTENU_REQUIS);
$e = "Il est nécessaire de fournir du contenu dans le corps de la requête pour créer une nouvelle ressource.";
self::ajouterMessage($e);
}
}
 
404,19 → 459,25
$Service = new $this->service(self::$config);
if (method_exists($Service, self::METHODE_DELETE)) {
$methodeDelete = self::METHODE_DELETE;
if ($Service->$methodeDelete($this->ressources, $paires)) {
$info = $Service->$methodeDelete($this->ressources);
if ($info === true) {
$this->envoyerEnteteStatutHttp(self::HTTP_CODE_SUPPRESSION_OK);
} else {
} else if ($info === false) {
$this->envoyerEnteteStatutHttp(self::HTTP_CODE_RESSOURCE_INTROUVABLE);
$e = "La ressource à supprimer est introuvable. Il se peut qu'elle ait été préalablement supprimé.";
self::ajouterMessage($e);
}
} else {
self::envoyerEnteteStatutHttp(self::HTTP_CODE_RESSOURCE_INTROUVABLE);
$e = "Le service '{$this->service}' ne contient pas la méthode '".self::METHODE_DELETE."' nécessaire ".
"lors de l'appel du service via la méthode HTTP DELETE (ou équivalant).";
trigger_error($e, E_USER_ERROR);
"lors de l'appel du service via la méthode HTTP GET.";
self::ajouterMessage($e);
}
}
} else {
$this->envoyerEnteteStatutHttp(self::HTTP_CODE_MAUVAISE_REQUETE);
$e = "Il est nécessaire d'indiquer dans l'url la ressource à supprimer.";
self::ajouterMessage($e);
}
}
457,6 → 518,18
}
/**
* Termine l'accès au serveur après envoir envoyer les messages.
*/
private static function cloreAccesServeur() {
// Gestion des exceptions et erreurs générées par les services
self::gererErreurs();
// Envoie des messages d'erreur et d'avertissement du serveur
self::envoyerMessages();
// Nous terminons le script
exit(0);
}
/**
* Si des exceptions ou des erreurs sont soulevées par le serveur ou les services, elles sont gérées par cette méthode.
* Si nous avec des erreurs d'un type différent d'E_USER_NOTICE (réservé au débogage), elle sont renvoyées sur la sortie
* standard (via echo).
495,5 → 568,28
}
}
}
/**
* Permet d'ajouter un message d'erreur ou d'avertissement qui sera envoyé au client.
* Le message doit être au format texte et en UTF-8.
* @param string $message le message à envoyer.
*/
public static function ajouterMessage($message) {
if (isset($message) && !empty($message)) {
self::$messages[] = $message;
}
}
/**
* Envoie au client les éventuels messages d'erreur et d'avertissement du Serveur.
* Le format d'envoie est text/plain encodé en UTF-8.
*/
private static function envoyerMessages() {
if (count(self::$messages) > 0) {
header("Content-Type: text/plain; charset=utf-8");
print implode("\n", self::$messages);
}
}
}
?>
/trunk/framework/RestService.php
15,24 → 15,49
* @license CECILL v2 <http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt>
* @since 0.3
* @version $Id$
* @link /doc/framework/
* @link http://www.tela-botanica.org/wikini/DevInformatiques/wakka.php?wiki=AppliBaseDocV3RestServeur
*/
abstract class RestService {
/** Objet de connection à la base de données. */
protected $bdd;
/** Objet de connection à la base de données.
* @deprecated Utiliser la methode getBdd().
* @see getBdd()
*/
protected $bdd = null;
/** Objet Rest Client. */
private $RestClient = null;
public function __construct($config) {
$this->config = $config;
// Connection à la base de données
$this->bdd = new Bdd();
$this->config = $config;
}
/**
* Méthode de connection à la base de données sur demande.
* Tous les services web n'ont pas besoin de s'y connecter.
*/
protected function getBdd() {
if (! isset($this->bdd)) {
$this->bdd = new bdd();
}
return $this->bdd;
}
/**
* Méthode permettant de faire appel à un client REST en fonction des besoins du service.
*/
protected function getRestClient() {
if (! isset($this->RestClient)) {
$this->RestClient = new RestClient();
}
return $this->RestClient;
}
/**
* Méthode appelée lors d'une requête HTTP de type GET.
*
* Si la consultation est un succès, le code statut HTTP retourné devrait être 200.
* Si la consultation est un succès, le code statut HTTP retourné sera 200. Dans tous les autres cas,
* la méthode devra retourner le code statut HTTP adéquate.
*
* @param array Morceaux de l'url servant à préciser la ressource concerné pour le service demandé.
* @param array Partie de l'url situé après le '?' servant à paramétrer le service demandé.
40,7 → 65,7
*/
public function consulter($ressources, $parametres) {
RestServeur::envoyerEnteteStatutHttp(RestServeur::HTTP_CODE_METHODE_NON_AUTORISE);
echo "Le service '".get_class($this)."' n'autorise pas la consultation.";
RestServeur::ajouterMessage("Le service '".get_class($this)."' n'autorise pas la consultation.");
}
/**
48,7 → 73,7
*
* La ressource à modifier est indiquée via l'url. Les données devant servir à la mise à jours sont passées dans le corps
* de la requête.
* Si la modification est un succès, le code statut HTTP retourné devrait être 201.
* Si la modification est un succès, la méthode devra retourner "true" et le code statut HTTP retourné sera 201.
*
* @param array Morceaux de l'url servant à préciser la ressource concerné pour le service demandé.
* @param array les données transférées dans le corps de la requête devant servir à la modification.
56,7 → 81,8
*/
public function modifier($ressources, $requeteDonnees) {
RestServeur::envoyerEnteteStatutHttp(RestServeur::HTTP_CODE_METHODE_NON_AUTORISE);
echo "Le service '".get_class($this)."' n'autorise pas la modification.";
RestServeur::ajouterMessage("Le service '".get_class($this)."' n'autorise pas la modification.");
return false;
}
/**
64,7 → 90,7
*
* L'identifiant de la ressource à ajouter est indiqué via l'url si on le connait par avance. Sinon, il doit être créé par
* le service. Dans ce dernier cas, le nouvel identifiant devrait être renvoyé dans le corps de la réponse.
* Si l'ajout est un succès, le code statut HTTP retourné devrait être 201.
* Si l'ajout est un succès, la méthode devra retourner "true" et le code statut HTTP retourné sera 201.
*
* @param array Morceaux de l'url servant à préciser la ressource concerné pour le service demandé.
* @param array les données transférées dans le corps de la requête devant servir à l'ajout.
72,13 → 98,19
*/
public function ajouter($ressources, $requeteDonnees) {
RestServeur::envoyerEnteteStatutHttp(RestServeur::HTTP_CODE_METHODE_NON_AUTORISE);
echo "Le service '".get_class($this)."' n'autorise pas la création.";
RestServeur::ajouterMessage("Le service '".get_class($this)."' n'autorise pas la création.");
return false;
}
/**
* Méthode appelée lors d'une requête HTTP de type DELETE (ou POST avec action=DELETE dans le corps de la requete).
*
* Si la suppression est un succès, le code statut HTTP retourné devrait être 204.
* Si la suppression est un succès, la méthode devra retourner "true" et le code statut HTTP retourné par
* RestServeur sera 204.
* Si la ressource à supprimer est introuvable, la méthode devra retourner "false" et le code statut HTTP
* retourné par RestServeur sera 404.
* Dans les autres cas de figure ou si vous souhaitez gérer vos propres codes de retour erreur, retourner
* la valeur null ou rien.
*
* @param array Morceaux de l'url servant à préciser la ressource concerné pour le service demandé.
* @return mixed une chaine indiquant le succès de l'opération ou rien.
85,7 → 117,8
*/
public function supprimer($ressources) {
RestServeur::envoyerEnteteStatutHttp(RestServeur::HTTP_CODE_METHODE_NON_AUTORISE);
echo "Le service '".get_class($this)."' n'autorise pas la suppression.";
RestServeur::ajouterMessage("Le service '".get_class($this)."' n'autorise pas la suppression.");
return null;
}
}
?>
/branches/v0.3-aleaume/framework/RestServeur.php
29,13 → 29,13
* Encodage en sortie : utf8
*
* @category Php 5.2
* @package Framework
* @package Framework
* @author Jean-Pascal MILCENT <jpm@tela-botanica.org>
* @copyright Copyright (c) 2010, Tela Botanica (accueil@tela-botanica.org)
* @license GPL v3 <http://www.gnu.org/licenses/gpl.txt>
* @license CECILL v2 <http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt>
* @license GPL v3 <http://www.gnu.org/licenses/gpl.txt>
* @license CECILL v2 <http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt>
* @since 0.3
* @version $Id$
* @version $Id$
* @link /doc/framework/
*/
// TODO : gerer les retours : dans ce controleur : code retour et envoi ...
95,6 → 95,12
* L'utiliser quand le serveur ou un service soulève une erreur ou une exception. */
const HTTP_CODE_ERREUR = '500';
/** Motif de l'epression régulière vérfiant la version de l'API. */
const MOTIF_API_VERSION = '/^[0-9]+(?:[.][0-9]+)*$/';
/** Motif de l'epression régulière vérfiant le nom du service. */
const MOTIF_SERVICE_NOM = '/^[a-z0-9]+(?:[-][a-z0-9]+)*$/';
/** Mettre à true pour activer l'affichage des messages d'erreurs et de débogage.
* @var boolean */
private static $debogageActivation = false;
143,6 → 149,11
* @var array
*/
private static $config = array();
 
/** Tableau contenant les messages d'erreur et/ou d'avertissement du Serveur.
* @var array
* */
private static $messages = array();
/** Codes HTTP. */
private static $http10 = array(
176,6 → 187,7
$this->initialiserRequeteDonnees();
$urlParts = $this->decouperUrlChemin();
$this->initialiserApiVersion(array_shift($urlParts));
$this->initialiserServiceNom(array_shift($urlParts));
$this->initialiserRessource($urlParts);
184,8 → 196,9
// Enregistrement en première position des autoload de la méthode gérant les classes des services
spl_autoload_register(array(get_class(), 'chargerClasse'));
} else {
self::envoyerEnteteStatutHttp(self::HTTP_CODE_ERREUR);
$e = "La classe Serveur du TBFRamework nécessite, pour fonctionner, l'accès aux variables serveurs REQUEST_URI, REQUEST_METHOD et QUERY_STRING.";
trigger_error($e, E_USER_ERROR);
self::ajouterMessage($e);
}
}
218,13 → 231,13
} else {
$url = $_SERVER['REQUEST_URI'];
}
//echo '<pre>'; print_r($_SERVER); echo '</pre>';
if (strlen($_SERVER['QUERY_STRING']) == 0) {
$tailleURL = strlen($url);
} else {
$tailleURL = -(strlen($_SERVER['QUERY_STRING']) + 1);
}
//echo '<br/>url : '.$url;
$urlChaine = '';
if (strpos($url, Config::get('serveur.baseURL')) !== false) {
$urlChaine = substr($url, strlen(Config::get('serveur.baseURL')), $tailleURL);
235,24 → 248,48
}
private function initialiserApiVersion($apiVersion) {
if (isset($apiVersion) && !empty($apiVersion)) {
if ($this->verifierApiVersion($apiVersion)) {
$this->apiVersion = $apiVersion;
self::$config['chemins']['api'] = Config::get('chemin_modules').$this->apiVersion.DS;
} else {
$e = "Aucune version d'API n'a été spécifié dans l'url qui doit avoir la forme suivante http://www.mondomaine.org/services/apiVersion/monService/";
trigger_error($e, E_USER_ERROR);
self::envoyerEnteteStatutHttp(self::HTTP_CODE_MAUVAISE_REQUETE);
$e = "Aucune version d'API n'a été spécifiée.\n".
"La version doit respecter l'expression régulière suivante : ".self::MOTIF_API_VERSION.".\n".
"L'url doit avoir la forme suivante : http://www.mondomaine.org/services/apiVersion/monService/";
self::ajouterMessage($e);
self::cloreAccesServeur();
}
}
private function verifierApiVersion($apiVersion) {
$apiOk = false;
if (isset($apiVersion) && !empty($apiVersion) && preg_match(self::MOTIF_API_VERSION, $apiVersion)) {
$apiOk = true;
}
return $apiOk;
}
private function initialiserServiceNom($serviceNom) {
if (isset($serviceNom) && !empty($serviceNom)) {
if ($this->verifierServiceNom($serviceNom)) {
$this->service = $this->traiterNomService($serviceNom);
} else {
$e = "Aucun service n'a été spécifié dans l'url qui doit avoir la forme suivante http://www.mondomaine.org/services/apiVersion/monService/";
trigger_error($e, E_USER_ERROR);
self::envoyerEnteteStatutHttp(self::HTTP_CODE_MAUVAISE_REQUETE);
$e = "Aucune nom de service n'a été spécifié.\n".
"La nom du service doit respecter l'expression régulière suivante : ".self::MOTIF_SERVICE_NOM.".\n".
"L'url doit avoir la forme suivante : http://www.mondomaine.org/services/apiVersion/monService/";
self::ajouterMessage($e);
self::cloreAccesServeur();
}
}
private function verifierServiceNom($serviceNom) {
$serviceNomOk = false;
if (isset($serviceNom) && !empty($serviceNom) && preg_match(self::MOTIF_SERVICE_NOM, $serviceNom)) {
$serviceNomOk = true;
}
return $serviceNomOk;
}
private function traiterNomService($serviceNom) {
return str_replace(' ', '', ucwords(str_replace('-', ' ', strtolower($serviceNom))));
}
294,20 → 331,28
if (class_exists($classe)) {
return null;
}
 
$classeTrouvee = false;
$chemins = array('', self::$config['chemins']['api']);
foreach ($chemins as $chemin) {
$chemin = $chemin.$classe.'.php';
if (file_exists($chemin)) {
require_once $chemin;
$classeTrouvee = true;
}
}
if ($classeTrouvee === false) {
self::envoyerEnteteStatutHttp(self::HTTP_CODE_RESSOURCE_INTROUVABLE);
$e = "La classe '$classe' du service n'a pas été trouvée par le serveur.\n".
"Cela peut signifier que le nom du service saisi comporte une erreur.";
self::ajouterMessage($e);
self::cloreAccesServeur();
}
}
/**
* Execute la requête.
*/
function executer() {
public function executer() {
switch ($this->methode) {
case 'GET':
$this->get();
322,11 → 367,13
$this->put();
break;
default :
$e = "La méthode HTTP '{$this->methode}' n'est pas prise en compte par ce serveur REST.";
trigger_error($e, E_USER_WARNING);
self::envoyerEnteteStatutHttp(self::HTTP_CODE_METHODE_NON_AUTORISE);
header('Allow: GET, POST, DELETE, PUT');
$e = "La méthode HTTP '{$this->methode}' n'est pas prise en compte par ce serveur REST.\n".
"Consulter l'entête Allow pour connaître les méthodes autorisées.";
self::ajouterMessage($e);
}
// Affichage des exceptions et erreurs générées par les services
$this->gererErreurs();
$this->cloreAccesServeur();
}
 
/**
341,9 → 388,10
$methodeGet = self::METHODE_GET;
$Service->$methodeGet($this->ressources, $this->parametres);
} else {
self::envoyerEnteteStatutHttp(self::HTTP_CODE_RESSOURCE_INTROUVABLE);
$e = "Le service '{$this->service}' ne contient pas la méthode '".self::METHODE_GET."' nécessaire ".
"lors de l'appel du service via la méthode HTTP GET.";
trigger_error($e, E_USER_ERROR);
self::ajouterMessage($e);
}
}
}
350,7 → 398,6
 
private function post() {
$paires = $this->parserDonneesRequete();
 
if (count($paires) != 0) {
if (isset($paires['action']) && $paires['action'] == 'DELETE') {// Altnative à l'utilisation de DELETE
$this->delete();
361,40 → 408,48
$Service = new $this->service(self::$config);
if (method_exists($Service, self::METHODE_POST)) {
$methodePost = self::METHODE_POST;
if ($Service->$methodePost($this->ressources, $paires)) {
$info = $Service->$methodePost($this->ressources, $paires);
if ($info === true) {
$this->envoyerEnteteStatutHttp(self::HTTP_CODE_CREATION_OK);
}
} else {
self::envoyerEnteteStatutHttp(self::HTTP_CODE_RESSOURCE_INTROUVABLE);
$e = "Le service '{$this->service}' ne contient pas la méthode '".self::METHODE_POST."' nécessaire ".
"lors de l'appel du service via la méthode HTTP POST.";
trigger_error($e, E_USER_ERROR);
"lors de l'appel du service via la méthode HTTP GET.";
self::ajouterMessage($e);
}
}
}
} else {
$this->envoyerEnteteStatutHttp(self::HTTP_CODE_CONTENU_REQUIS);
$e = "Le service '{$this->service}' requiert de fournir le contenu à modifier dans le corps ".
"de la requête avec la méthode HTTP POST.";
self::ajouterMessage($e);
}
}
 
private function put() {
$paires = $this->parserDonneesRequete();
 
if (count($paires) != 0) {
if ($this->service != null) {
$Service = new $this->service(self::$config);
if (method_exists($Service, self::METHODE_PUT)) {
$methodePut = self::METHODE_PUT;
if ($Service->$methodePut($this->ressources, $paires)) {
$info = $Service->$methodePut($this->ressources, $paires);
if ($info === true) {
$this->envoyerEnteteStatutHttp(self::HTTP_CODE_CREATION_OK);
}
} else {
self::envoyerEnteteStatutHttp(self::HTTP_CODE_RESSOURCE_INTROUVABLE);
$e = "Le service '{$this->service}' ne contient pas la méthode '".self::METHODE_PUT."' nécessaire ".
"lors de l'appel du service via la méthode HTTP PUT (ou équivalant).";
trigger_error($e, E_USER_ERROR);
"lors de l'appel du service via la méthode HTTP GET.";
self::ajouterMessage($e);
}
}
} else {
$this->envoyerEnteteStatutHttp(self::HTTP_CODE_CONTENU_REQUIS);
$e = "Il est nécessaire de fournir du contenu dans le corps de la requête pour créer une nouvelle ressource.";
self::ajouterMessage($e);
}
}
 
404,19 → 459,25
$Service = new $this->service(self::$config);
if (method_exists($Service, self::METHODE_DELETE)) {
$methodeDelete = self::METHODE_DELETE;
if ($Service->$methodeDelete($this->ressources, $paires)) {
$info = $Service->$methodeDelete($this->ressources);
if ($info === true) {
$this->envoyerEnteteStatutHttp(self::HTTP_CODE_SUPPRESSION_OK);
} else {
} else if ($info === false) {
$this->envoyerEnteteStatutHttp(self::HTTP_CODE_RESSOURCE_INTROUVABLE);
$e = "La ressource à supprimer est introuvable. Il se peut qu'elle ait été préalablement supprimé.";
self::ajouterMessage($e);
}
} else {
self::envoyerEnteteStatutHttp(self::HTTP_CODE_RESSOURCE_INTROUVABLE);
$e = "Le service '{$this->service}' ne contient pas la méthode '".self::METHODE_DELETE."' nécessaire ".
"lors de l'appel du service via la méthode HTTP DELETE (ou équivalant).";
trigger_error($e, E_USER_ERROR);
"lors de l'appel du service via la méthode HTTP GET.";
self::ajouterMessage($e);
}
}
} else {
$this->envoyerEnteteStatutHttp(self::HTTP_CODE_MAUVAISE_REQUETE);
$e = "Il est nécessaire d'indiquer dans l'url la ressource à supprimer.";
self::ajouterMessage($e);
}
}
457,6 → 518,18
}
/**
* Termine l'accès au serveur après envoir envoyer les messages.
*/
private static function cloreAccesServeur() {
// Gestion des exceptions et erreurs générées par les services
self::gererErreurs();
// Envoie des messages d'erreur et d'avertissement du serveur
self::envoyerMessages();
// Nous terminons le script
exit(0);
}
/**
* Si des exceptions ou des erreurs sont soulevées par le serveur ou les services, elles sont gérées par cette méthode.
* Si nous avec des erreurs d'un type différent d'E_USER_NOTICE (réservé au débogage), elle sont renvoyées sur la sortie
* standard (via echo).
495,5 → 568,28
}
}
}
/**
* Permet d'ajouter un message d'erreur ou d'avertissement qui sera envoyé au client.
* Le message doit être au format texte et en UTF-8.
* @param string $message le message à envoyer.
*/
public static function ajouterMessage($message) {
if (isset($message) && !empty($message)) {
self::$messages[] = $message;
}
}
/**
* Envoie au client les éventuels messages d'erreur et d'avertissement du Serveur.
* Le format d'envoie est text/plain encodé en UTF-8.
*/
private static function envoyerMessages() {
if (count(self::$messages) > 0) {
header("Content-Type: text/plain; charset=utf-8");
print implode("\n", self::$messages);
}
}
}
?>
/branches/v0.3-aleaume/framework/RestService.php
19,20 → 19,45
*/
abstract class RestService {
/** Objet de connection à la base de données. */
protected $bdd;
/** Objet de connection à la base de données.
* @deprecated Utiliser la methode getBdd().
* @see getBdd()
*/
protected $bdd = null;
/** Objet Rest Client. */
private $RestClient = null;
public function __construct($config) {
$this->config = $config;
// Connection à la base de données
$this->bdd = new Bdd();
$this->config = $config;
}
/**
* Méthode de connection à la base de données sur demande.
* Tous les services web n'ont pas besoin de s'y connecter.
*/
protected function getBdd() {
if (! isset($this->bdd)) {
$this->bdd = new bdd();
}
return $this->bdd;
}
/**
* Méthode permettant de faire appel à un client REST en fonction des besoins du service.
*/
protected function getRestClient() {
if (! isset($this->RestClient)) {
$this->RestClient = new RestClient();
}
return $this->RestClient;
}
/**
* Méthode appelée lors d'une requête HTTP de type GET.
*
* Si la consultation est un succès, le code statut HTTP retourné devrait être 200.
* Si la consultation est un succès, le code statut HTTP retourné sera 200. Dans tous les autres cas,
* la méthode devra retourner le code statut HTTP adéquate.
*
* @param array Morceaux de l'url servant à préciser la ressource concerné pour le service demandé.
* @param array Partie de l'url situé après le '?' servant à paramétrer le service demandé.
40,7 → 65,7
*/
public function consulter($ressources, $parametres) {
RestServeur::envoyerEnteteStatutHttp(RestServeur::HTTP_CODE_METHODE_NON_AUTORISE);
echo "Le service '".get_class($this)."' n'autorise pas la consultation.";
RestServeur::ajouterMessage("Le service '".get_class($this)."' n'autorise pas la consultation.");
}
/**
48,7 → 73,7
*
* La ressource à modifier est indiquée via l'url. Les données devant servir à la mise à jours sont passées dans le corps
* de la requête.
* Si la modification est un succès, le code statut HTTP retourné devrait être 201.
* Si la modification est un succès, la méthode devra retourner "true" et le code statut HTTP retourné sera 201.
*
* @param array Morceaux de l'url servant à préciser la ressource concerné pour le service demandé.
* @param array les données transférées dans le corps de la requête devant servir à la modification.
56,7 → 81,8
*/
public function modifier($ressources, $requeteDonnees) {
RestServeur::envoyerEnteteStatutHttp(RestServeur::HTTP_CODE_METHODE_NON_AUTORISE);
echo "Le service '".get_class($this)."' n'autorise pas la modification.";
RestServeur::ajouterMessage("Le service '".get_class($this)."' n'autorise pas la modification.");
return false;
}
/**
64,7 → 90,7
*
* L'identifiant de la ressource à ajouter est indiqué via l'url si on le connait par avance. Sinon, il doit être créé par
* le service. Dans ce dernier cas, le nouvel identifiant devrait être renvoyé dans le corps de la réponse.
* Si l'ajout est un succès, le code statut HTTP retourné devrait être 201.
* Si l'ajout est un succès, la méthode devra retourner "true" et le code statut HTTP retourné sera 201.
*
* @param array Morceaux de l'url servant à préciser la ressource concerné pour le service demandé.
* @param array les données transférées dans le corps de la requête devant servir à l'ajout.
72,13 → 98,19
*/
public function ajouter($ressources, $requeteDonnees) {
RestServeur::envoyerEnteteStatutHttp(RestServeur::HTTP_CODE_METHODE_NON_AUTORISE);
echo "Le service '".get_class($this)."' n'autorise pas la création.";
RestServeur::ajouterMessage("Le service '".get_class($this)."' n'autorise pas la création.");
return false;
}
/**
* Méthode appelée lors d'une requête HTTP de type DELETE (ou POST avec action=DELETE dans le corps de la requete).
*
* Si la suppression est un succès, le code statut HTTP retourné devrait être 204.
* Si la suppression est un succès, la méthode devra retourner "true" et le code statut HTTP retourné par
* RestServeur sera 204.
* Si la ressource à supprimer est introuvable, la méthode devra retourner "false" et le code statut HTTP
* retourné par RestServeur sera 404.
* Dans les autres cas de figure ou si vous souhaitez gérer vos propres codes de retour erreur, retourner
* la valeur null ou rien.
*
* @param array Morceaux de l'url servant à préciser la ressource concerné pour le service demandé.
* @return mixed une chaine indiquant le succès de l'opération ou rien.
85,7 → 117,8
*/
public function supprimer($ressources) {
RestServeur::envoyerEnteteStatutHttp(RestServeur::HTTP_CODE_METHODE_NON_AUTORISE);
echo "Le service '".get_class($this)."' n'autorise pas la suppression.";
RestServeur::ajouterMessage("Le service '".get_class($this)."' n'autorise pas la suppression.");
return null;
}
}
?>