Crvi/app/controllers/Local_Controller.php
2026-01-20 07:54:37 +01:00

358 lines
12 KiB
PHP

<?php
declare(strict_types=1);
namespace ESI_CRVI_AGENDA\controllers;
use ESI_CRVI_AGENDA\models\CRVI_Local_Model;
use ESI_CRVI_AGENDA\helpers\Api_Helper;
class CRVI_Local_Controller {
public static function register_cpt() {
register_post_type('local', [
'label' => 'Locaux',
'labels' => [
'name' => 'Locaux',
'singular_name' => 'Local',
'add_new' => 'Ajouter un local',
'add_new_item' => 'Ajouter un nouveau local',
'edit_item' => 'Modifier le local',
'new_item' => 'Nouveau local',
'view_item' => 'Voir le local',
'search_items' => 'Rechercher un local',
'not_found' => 'Aucun local trouvé',
'not_found_in_trash' => 'Aucun local dans la corbeille',
],
'public' => true,
'show_in_menu' => true,
'menu_position' => 23,
'menu_icon' => 'dashicons-building',
'supports' => ['title'],
'has_archive' => false,
'show_in_rest' => true,
]);
}
public static function register_routes() {
register_rest_route('crvi/v1', '/locaux', [
[
'methods' => 'GET',
'callback' => [self::class, 'get_items'],
'permission_callback' => '__return_true',
],
[
'methods' => 'POST',
'callback' => [self::class, 'create_item'],
'permission_callback' => [self::class, 'can_edit'],
],
]);
register_rest_route('crvi/v1', '/locaux/disponibles', [
[
'methods' => 'GET',
'callback' => [self::class, 'filtrer_disponibles'],
'permission_callback' => '__return_true',
'args' => [
'date_debut' => [
'required' => false,
'type' => 'string',
'description' => 'Date de début (YYYY-MM-DD)',
],
'date_fin' => [
'required' => false,
'type' => 'string',
'description' => 'Date de fin (YYYY-MM-DD)',
],
'heure_debut' => [
'required' => false,
'type' => 'string',
'description' => 'Heure de début (HH:MM)',
],
'heure_fin' => [
'required' => false,
'type' => 'string',
'description' => 'Heure de fin (HH:MM)',
],
],
],
]);
register_rest_route('crvi/v1', '/locaux/import', [
[
'methods' => 'POST',
'callback' => [self::class, 'import_csv'],
'permission_callback' => [self::class, 'can_edit'],
'args' => [
'file' => [
'required' => true,
'description' => 'Fichier CSV à importer',
'type' => 'file',
],
],
],
]);
register_rest_route('crvi/v1', '/locaux/(?P<id>\\d+)', [
[
'methods' => 'GET',
'callback' => [self::class, 'get_item'],
'permission_callback' => '__return_true',
],
[
'methods' => 'PUT,PATCH',
'callback' => [self::class, 'update_item'],
'permission_callback' => [self::class, 'can_edit'],
],
[
'methods' => 'DELETE',
'callback' => [self::class, 'delete_item'],
'permission_callback' => [self::class, 'can_delete'],
],
]);
}
public static function get_items($request) {
$items = CRVI_Local_Model::all();
return Api_Helper::json_success($items);
}
public static function get_item($request) {
$id = (int) $request['id'];
$item = CRVI_Local_Model::load($id);
if (!$item) {
return Api_Helper::json_error('Local introuvable', 404);
}
return Api_Helper::json_success($item);
}
/**
* Filtre les locaux disponibles selon les critères fournis
* @param WP_REST_Request $request
* @return WP_REST_Response
*/
public static function filtrer_disponibles($request) {
$date_debut = $request->get_param('date_debut');
$date_fin = $request->get_param('date_fin');
$heure_debut = $request->get_param('heure_debut');
$heure_fin = $request->get_param('heure_fin');
// Récupérer tous les locaux
$tous_locaux = CRVI_Local_Model::all();
// Si aucun critère de temps n'est fourni, retourner tous les locaux
if (empty($date_debut) && empty($date_fin) && empty($heure_debut) && empty($heure_fin)) {
return Api_Helper::json_success($tous_locaux);
}
// Filtrer les locaux disponibles selon les critères
$locaux_disponibles = [];
foreach ($tous_locaux as $local) {
$disponible = true;
// Vérifier la disponibilité selon les critères fournis
if ($date_debut && $date_fin) {
// Vérifier s'il y a des conflits d'événements dans cette période
$conflits = self::verifier_conflits_local($local['id'], $date_debut, $date_fin, $heure_debut, $heure_fin);
if (!empty($conflits)) {
$disponible = false;
}
}
if ($disponible) {
$locaux_disponibles[] = $local;
}
}
return Api_Helper::json_success($locaux_disponibles);
}
/**
* Vérifie s'il y a des conflits d'événements pour un local donné
* @param int $local_id
* @param string $date_debut
* @param string $date_fin
* @param string $heure_debut
* @param string $heure_fin
* @return array
*/
private static function verifier_conflits_local($local_id, $date_debut, $date_fin, $heure_debut = null, $heure_fin = null) {
global $wpdb;
$table_events = $wpdb->prefix . 'crvi_agenda';
$where_conditions = ['local_id = %d'];
$where_values = [$local_id];
// Ajouter les conditions de date
if ($date_debut && $date_fin) {
$where_conditions[] = '(
(date_rdv BETWEEN %s AND %s) OR
(date_fin BETWEEN %s AND %s) OR
(%s BETWEEN date_rdv AND date_fin) OR
(%s BETWEEN date_rdv AND date_fin)
)';
$where_values = array_merge($where_values, [$date_debut, $date_fin, $date_debut, $date_fin, $date_debut, $date_fin]);
}
// Ajouter les conditions d'heure si fournies
if ($heure_debut && $heure_fin) {
$where_conditions[] = '(
(heure_rdv BETWEEN %s AND %s) OR
(heure_fin BETWEEN %s AND %s) OR
(%s BETWEEN heure_rdv AND heure_fin) OR
(%s BETWEEN heure_rdv AND heure_fin)
)';
$where_values = array_merge($where_values, [$heure_debut, $heure_fin, $heure_debut, $heure_fin, $heure_debut, $heure_fin]);
}
$where_clause = implode(' AND ', $where_conditions);
$query = $wpdb->prepare(
"SELECT * FROM {$table_events} WHERE {$where_clause}",
$where_values
);
return $wpdb->get_results($query, ARRAY_A);
}
public static function create($request) {
$data = $request->get_json_params();
$model = new CRVI_Local_Model();
$validation = self::validate_local_data($data);
if (is_wp_error($validation)) {
return Api_Helper::json_error($validation->get_error_message(), 400);
}
$result = $model->create($data);
if (is_wp_error($result)) {
return $result;
}
return Api_Helper::json_success([
'id' => $result,
'nom' => $data['nom'],
'message' => 'Local créé avec succès'
]);
}
public static function update_item($request) {
$id = (int) $request['id'];
$model = new CRVI_Local_Model();
$result = $model->update($id, $request->get_json_params());
if (is_wp_error($result)) {
return $result;
}
return Api_Helper::json_success(['id' => $id]);
}
public static function delete_item($request) {
$id = (int) $request['id'];
$model = new CRVI_Local_Model();
$result = $model->delete($id);
if (is_wp_error($result)) {
return $result;
}
return Api_Helper::json_success(['id' => $id, 'deleted' => true]);
}
/**
* Import CSV de locaux via REST
* @param WP_REST_Request $request
* @return array
*/
public static function import_csv($request) {
if (!current_user_can('edit_posts')) {
return Api_Helper::json_error('Non autorisé', 403);
}
$file = $request->get_file_params()['file'] ?? null;
if (!$file || !is_uploaded_file($file['tmp_name'])) {
return Api_Helper::json_error('Fichier CSV manquant ou invalide', 400);
}
$handle = fopen($file['tmp_name'], 'r');
if (!$handle) {
return Api_Helper::json_error('Impossible d\'ouvrir le fichier', 400);
}
$header = fgetcsv($handle, 0, ',');
$results = [];
$row_num = 1;
while (($row = fgetcsv($handle, 0, ',')) !== false) {
$row_num++;
$data = array_combine($header, $row);
$model = new CRVI_Local_Model();
$result = $model->create($data);
$results[] = [
'ligne' => $row_num,
'data' => $data,
'resultat' => $result
];
}
fclose($handle);
return Api_Helper::json_success(['import' => $results]);
}
// Permissions personnalisées
public static function can_edit() {
return current_user_can('edit_posts');
}
public static function can_delete() {
return current_user_can('delete_posts');
}
// Handler pour l'import CSV via formulaire admin
public static function import_csv_admin() {
if (!current_user_can('edit_posts')) {
wp_die('Non autorisé');
}
check_admin_referer('crvi_import_local');
if (empty($_FILES['import_csv']['tmp_name'])) {
wp_redirect(admin_url('admin.php?page=crvi_agenda&import=error&msg=Fichier manquant'));
exit;
}
$file = $_FILES['import_csv']['tmp_name'];
$handle = fopen($file, 'r');
if (!$handle) {
wp_redirect(admin_url('admin.php?page=crvi_agenda&import=error&msg=Impossible d\'ouvrir le fichier'));
exit;
}
$header = fgetcsv($handle, 0, ',');
$created = $updated = $errors = 0;
while (($row = fgetcsv($handle, 0, ',')) !== false) {
$data = array_combine($header, $row);
$data = array_combine(
array_map(function($k) { return sanitize_title($k); }, array_keys($data)),
array_map('trim', array_values($data))
);
$model = new CRVI_Local_Model();
$result = $model->create($data);
if (is_numeric($result)) {
$created++;
} elseif (is_wp_error($result) && $result->get_error_code() === '409') {
// Nom déjà utilisé - on pourrait mettre à jour au lieu d'ignorer
$errors++;
} else {
$errors++;
}
}
fclose($handle);
$msg = "Créés: $created, Erreurs: $errors";
wp_redirect(admin_url('admin.php?page=crvi_agenda&import=success&msg=' . urlencode($msg)));
exit;
}
public static function validate_local_data($data) {
if (empty($data['nom'])) {
return new \WP_Error('missing_nom', 'Le nom du local est obligatoire');
}
if (!empty($data['capacite']) && !is_numeric($data['capacite'])) {
return new \WP_Error('invalid_capacite', 'La capacité doit être un nombre');
}
return true;
}
}