Générer un planning sous forme de tableau HTML

Avatar du membre
Administrateur PHPfrance
Administrateur PHPfrance | 13231 Messages

29 déc. 2010, 16:54

Peut être qu'une petite recherche Google t'aurais apporté la réponse ;)

http://www.php.net/manual/fr/language.o ... ng.members
Connaître son ignorance est la meilleure part de la connaissance
Pour un code lisible : n'hésitez pas à sauter des lignes et indenter

twitter - site perso - Github - Zend Certified Engineer

Petit nouveau ! | 6 Messages

15 mars 2011, 17:41

re amis du WEB je voudrais savoir comment avec ce script il est possible d'avoir 2 taches a la même heure le même jour :shock: ?

merci d'avance
Modifié en dernier par eristyl le 15 mars 2011, 18:02, modifié 1 fois.

ViPHP
xTG
ViPHP | 7331 Messages

15 mars 2011, 17:54

Le script a été fait pour une gestion de cours.
Or on a rarement deux cours à deux endroits différents se déroulant au même moment.
Donc je doute que cela soit géré. ;)

Petit nouveau ! | 6 Messages

15 mars 2011, 18:05

Le script a été fait pour une gestion de cours.
Or on a rarement deux cours à deux endroits différents se déroulant au même moment.
Donc je doute que cela soit géré. ;)
Justement connais-tu une institution qui ne gère qu'un seul cour a une meme heure ?
Non, ou que ce soit tu peux avoir plusieur cours en meme temps.
(Je parle bien entendu de planning général, en effet pour le planning d'une personne le problème ne se pose pas).

Modérateur PHPfrance
Modérateur PHPfrance | 6373 Messages

18 mars 2011, 23:47

En effet quand je l'ai cree nous n'avions qu'une seule salle, et mon outil ne gerait pas le cas du tout. C'est un peu stupide je le reconnais mais j'avais une date limite et du coup j'ai focalise sur le cas present, sans penser a ca. Avec cette classe tu ne pourras donc pas avoir deux evenements au meme moment a deux endroits differents (en fait si tu peux mais un seul sera affiche)

Je dois faire la modification, le probleme c'est quil faudra donc gerer du colspan ET du rowspan, et c'est galere. Il y a de l'algo a faire et je n'ai pas eu le temps de m'y pencher :)

Petit nouveau ! | 6 Messages

01 avr. 2011, 15:34

Si tu as le temps de t'y pencher ou de me donner des conseils je suis prenant =D parce que la vraiment je bloque.
merci

Petit nouveau ! | 2 Messages

09 nov. 2011, 12:13

Merci beaucoup pour ce script qui vient de me faire gagner un temps fou :)

Cependant, j'ai un petit problème/question : Je passe la variable $pas=15 en argument, les cases sont bien divisées en 15 minutes. Mais si je donne un début de cours par exemple à 17H15 (17:15:00), et bien le script recale automatiquement à 17H00. Quelqu'un aurait-il une solution ?

Autrement, c'est un beau travail.
Merci encore,

FAB

Modérateur PHPfrance
Modérateur PHPfrance | 6373 Messages

09 nov. 2011, 19:04

Pux-tu nous montrer comment tu fais car normalement ca fonctionne, plus haut dans le thread quelqu'un avait d'ailleurs le meme soucis, et modifiait le constructeur et non l'instanciation.

Petit nouveau ! | 2 Messages

14 nov. 2011, 20:42

Voici :

Code : Tout sélectionner

<?php include('Planning.php'); include('PlanningCellule.php'); include('PlanningMapper.php'); $contenusCellules[] = new PlanningCellule(1,'17:15:00','19:00:00','#008000','<b>Zeus</b><br />B1/1'); $contenusCellules[] = new PlanningCellule(1,'19:00:00','21:00:00','#7CCAF4','<b>Ryle</b><br />A2'); $planning = new Planning(1, 6, 540, 1320, 15, $contenusCellules); $planning->afficherHtmlTable(); ?>
Merci,
Fabrice

Modérateur PHPfrance
Modérateur PHPfrance | 6373 Messages

04 avr. 2013, 14:21

Mise à jour pour gérer plusieurs salles:

Classe principale:
<?php
namespace Virgule\Bundle\MainBundle\Entity\Planning;

use Virgule\Bundle\MainBundle\Entity\Planning\HeaderCell;
use Virgule\Bundle\MainBundle\Entity\Planning\PlanningCell;
use Virgule\Bundle\MainBundle\Entity\CourseHydrated;

class Planning {
    // cells[jour][heure_debut]
    
    private $dayStart;
    private $dayEnd;
    private $startTime;
    private $endTime;
    
    public static $cellSize = 30;
    
    private $header = Array();
    private $rows = Array();
    
    private $classRooms = Array();
    
    public function __construct($courses) {
        $this->dayStart = 1;
        $this->dayEnd = 6;
        $this->startTime = new \DateTime('08:00');
        $this->endTime = new \DateTime('21:30');
        
        $this->initPlanning($courses);
        $this->initHeader();
        $this->addCourses($courses);
    }
    
    public function getRows() {
        return $this->rows;
    }
    
    public function getHeader() {
        return $this->header;
    }
    
    private function initHeader() {
        for ($day = $this->dayStart; $day <= $this->dayEnd; $day++) {
            $this->header[$day] = new HeaderCell($day);
            foreach ($this->classRooms as $classRoomId => $classRoomName) {
                $this->header[$day]->addClassRoom($classRoomId, $classRoomName);
            }
        }
    }
    
    private function initPlanning($courses) {
        $startTimeCell = clone $this->startTime;
        $endTimeCell = clone $this->startTime;
        $endTimeCell->modify("+" . self::$cellSize . " minutes");
        
        foreach ($courses as $course) {
            $this->storeClassRoom($course->getClassRoomId(), $course->getClassRoomName());
        }
        
        if (count($this->classRooms) == 0) {
            $this->storeClassRoom(0, "");
        }
        
        while ($startTimeCell <= $this->endTime) {
            $timeIndex = $startTimeCell->format('H:i');
            
            $this->rows[$timeIndex] = new PlanningRow($startTimeCell->format('H:i'), $endTimeCell->format('H:i'));
            
            for ($day = $this->dayStart; $day <= $this->dayEnd; $day++) {
                foreach ($this->classRooms as $classRoomId => $classRoomName) {
                    $this->rows[$timeIndex]->initCell($day, $classRoomId);
                }
            }
            $startTimeCell->modify("+" . self::$cellSize . " minutes");
            $endTimeCell->modify("+" . self::$cellSize . " minutes");
        }
    }
    
    private function addCourses($courses) {
        foreach($courses as $course) {
            $this->addCourse($course);
        }
    }
    private function addCourse(CourseHydrated $course) {
        $t = $course->getStartTime();
        if (array_key_exists($t->format('H:i'), $this->rows)) {
            $this->rows[$t->format('H:i')]->addCell($course);
            $timeCell = clone $course->getStartTime();
            $timeCell->modify("+" . self::$cellSize . " minutes");

            while ($timeCell < $course->getEndTime()) {
                $timeIndex = $timeCell->format('H:i');
                $this->rows[$timeIndex]->removeCell($course->getDayOfWeek(), $course->getClassRoomId());
                $timeCell->modify("+" . self::$cellSize . " minutes");
            }
        }
    }
    
    private function sortCells() {
        foreach ($this->rows as $time => $row) {
            $this->rows[$time] = ksort($row->getCells());
            foreach ($row as $day => $cells) {
                $this->rows[$time][$day] = krsort($cells);
            }
        }
    }
    
    private function storeClassRoom($classRoomId, $classRoomLabel) {
        if (! array_key_exists($classRoomId, $this->classRooms)) {
            $this->classRooms[$classRoomId] = $classRoomLabel;
        }
    }
}
?>
Cellule:
<?php
namespace Virgule\Bundle\MainBundle\Entity\Planning;

use Virgule\Bundle\MainBundle\Entity\Planning\HeaderCell;
use Virgule\Bundle\MainBundle\Entity\Planning\PlanningCell;
use Virgule\Bundle\MainBundle\Entity\CourseHydrated;

class Planning {
    // cells[jour][heure_debut]
    
    private $dayStart;
    private $dayEnd;
    private $startTime;
    private $endTime;
    
    public static $cellSize = 30;
    
    private $header = Array();
    private $rows = Array();
    
    private $classRooms = Array();
    
    public function __construct($courses) {
        $this->dayStart = 1;
        $this->dayEnd = 6;
        $this->startTime = new \DateTime('08:00');
        $this->endTime = new \DateTime('21:30');
        
        $this->initPlanning($courses);
        $this->initHeader();
        $this->addCourses($courses);
    }
    
    public function getRows() {
        return $this->rows;
    }
    
    public function getHeader() {
        return $this->header;
    }
    
    private function initHeader() {
        for ($day = $this->dayStart; $day <= $this->dayEnd; $day++) {
            $this->header[$day] = new HeaderCell($day);
            foreach ($this->classRooms as $classRoomId => $classRoomName) {
                $this->header[$day]->addClassRoom($classRoomId, $classRoomName);
            }
        }
    }
    
    private function initPlanning($courses) {
        $startTimeCell = clone $this->startTime;
        $endTimeCell = clone $this->startTime;
        $endTimeCell->modify("+" . self::$cellSize . " minutes");
        
        foreach ($courses as $course) {
            $this->storeClassRoom($course->getClassRoomId(), $course->getClassRoomName());
        }
        
        if (count($this->classRooms) == 0) {
            $this->storeClassRoom(0, "");
        }
        
        while ($startTimeCell <= $this->endTime) {
            $timeIndex = $startTimeCell->format('H:i');
            
            $this->rows[$timeIndex] = new PlanningRow($startTimeCell->format('H:i'), $endTimeCell->format('H:i'));
            
            for ($day = $this->dayStart; $day <= $this->dayEnd; $day++) {
                foreach ($this->classRooms as $classRoomId => $classRoomName) {
                    $this->rows[$timeIndex]->initCell($day, $classRoomId);
                }
            }
            $startTimeCell->modify("+" . self::$cellSize . " minutes");
            $endTimeCell->modify("+" . self::$cellSize . " minutes");
        }
    }
    
    private function addCourses($courses) {
        foreach($courses as $course) {
            $this->addCourse($course);
        }
    }
    private function addCourse(CourseHydrated $course) {
        $t = $course->getStartTime();
        if (array_key_exists($t->format('H:i'), $this->rows)) {
            $this->rows[$t->format('H:i')]->addCell($course);
            $timeCell = clone $course->getStartTime();
            $timeCell->modify("+" . self::$cellSize . " minutes");

            while ($timeCell < $course->getEndTime()) {
                $timeIndex = $timeCell->format('H:i');
                $this->rows[$timeIndex]->removeCell($course->getDayOfWeek(), $course->getClassRoomId());
                $timeCell->modify("+" . self::$cellSize . " minutes");
            }
        }
    }
    
    private function sortCells() {
        foreach ($this->rows as $time => $row) {
            $this->rows[$time] = ksort($row->getCells());
            foreach ($row as $day => $cells) {
                $this->rows[$time][$day] = krsort($cells);
            }
        }
    }
    
    private function storeClassRoom($classRoomId, $classRoomLabel) {
        if (! array_key_exists($classRoomId, $this->classRooms)) {
            $this->classRooms[$classRoomId] = $classRoomLabel;
        }
    }
}
?>
Cellule d'en-tête:
<?php
namespace Virgule\Bundle\MainBundle\Entity\Planning;

class HeaderCell {
    private $day;
    
    private $classRooms = Array();
    
    public function __construct($day) {
        $this->day = $day;
    }
    
    public function getDay() {
        return $this->day;
    }
    
    public function getClassRooms() {
        return $this->classRooms;
    }
    
    public function addClassRoom($classRoomId, $classRoomName) {
        $this->classRooms[$classRoomId] = $classRoomName;
    }
}
?>
Classe de ligne:
<?php
namespace Virgule\Bundle\MainBundle\Entity\Planning;

use Virgule\Bundle\MainBundle\Entity\CourseHydrated;
use Virgule\Bundle\MainBundle\Entity\Planning\PlanningCell;

class PlanningRow {
    private $startTime;
    private $endTime;
    
    private $cells = Array();
    
    public function __construct($startTime, $endTime) {
        $this->startTime = $startTime;
        $this->endTime = $endTime;
    }
    
    public function getStartTime() {
        return $this->startTime;
    }
    
    public function getEndTime() {
        return $this->endTime;
    }
    
    public function getCells() {
        return $this->cells;
    }
    
    public function initCell($day, $classRoom) {
        $this->cells[$day][$classRoom] = new PlanningCell();
    }
            
    public function addCell(CourseHydrated $course = null) {
        $this->cells[$course->getDayOfWeek()][$course->getClassRoomId()] = new PlanningCell($course);
    }
    
    public function removeCell($day, $classRoom) {
        $this->cells[$day][$classRoom] = null;
    }
}
?>
Ma classe de cours qui contient tout:
<?php
namespace Virgule\Bundle\MainBundle\Entity;

class CourseHydrated {
    
    private $courseId;
    private $dayOfWeek;
    private $startTime;
    private $endTime;
    private $alternateStartdate;
    private $alternateEnddate;
    private $classLevelId;
    private $classLevelLabel;
    private $classLevelColorCode;
    private $teachers = Array();
    private $classRoomId;
    private $classRoomName;
    private $nbStudents;

    public function __construct($id, $dayOfWeek, $startTime, $endTime, $alternateStartdate, $alternateEnddate, $nbStudents, $classLevelId, $classLevelLabel, $classLevelColorCode, $teachers, $classRoomId, $classRoomName) {
        $this->courseId = $id;
        $this->dayOfWeek = $dayOfWeek;
        $this->startTime = $startTime;
        $this->endTime = $endTime;
        $this->alternateStartdate = $alternateStartdate;
        $this->alternateEnddate = $alternateEnddate;
        $this->classLevelId = $classLevelId;
        $this->classLevelLabel = $classLevelLabel;
        $this->classLevelColorCode = $classLevelColorCode;
        $this->teachers = $teachers;
        $this->classRoomId = $classRoomId;
        $this->classRoomName = $classRoomName;
        $this->nbStudents = $nbStudents;
    }

    public function getId() {
        return $this->courseId;
    }

    public function getDayOfWeek() {
        return $this->dayOfWeek;
    }

    public function getStartTime() {
        return $this->startTime;
    }

    public function getEndTime() {
        return $this->endTime;
    }

    public function getAlternateStartdate() {
        return $this->alternateStartdate;
    }

    public function getAlternateEnddate() {
        return $this->alternateEnddate;
    }

    public function getClassLevelId() {
        return $this->classLevelId;
    }

    public function getClassLevelLabel() {
        return $this->classLevelLabel;
    }
    
    public function getClassLevelColorCode() {
        return $this->classLevelColorCode;
    }

    public function getTeachers() {
        return $this->teachers;
    }

    public function getClassRoomId() {
        return $this->classRoomId;
    }

    public function getClassRoomName() {
        return $this->classRoomName;
    }

    public function getNbStudents() {
        return $this->nbStudents;
    }
}
?>
Template TWIG:
{% block main_content %}
{% set currentSemester = app.session.get('currentSemester') %}
<div class="widget-box">
    <div class="widget-title">
            <span class="icon">
                    <i class="icon-th"></i>
            </span>
            <h5>Planning du {{ currentSemester.startDate|date("d/m/Y") }} au {{ currentSemester.endDate|date("d/m/Y") }}</h5>
    </div>
    <div class="widget-content nopadding">
        <table id="planning" class="table table-bordered">
            <thead>
                <tr>
                    <th rowspan="2">&nbsp;</th>
                    {% for headerCell in headerCells %}
                        <th colspan="{{ headerCell.classRooms | length }}">{{ headerCell.day | day }}</th>
                    {% endfor %}
                </tr>
                <tr>
                    {% for headerCell in headerCells %}
                        {% for classRoom in headerCell.classRooms %}
                            <th>{{ classRoom }}</th>
                        {% endfor %}
                    {% endfor %}
                </tr>
            </thead>
            {% for row in planningRows %}
            <tr>
                <th>{{ row.startTime | date('H:i') }} - {{ row.endTime | date('H:i')}}</th>
                {% for dayCells in row.cells %}
                    {% for classRoomCell in dayCells %}
                        {% if classRoomCell is not null %}
                            <td class="center" {% if classRoomCell.rowspan > 0 %} rowspan="{{ classRoomCell.rowspan }}" style="border: 3px solid {{ classRoomCell.course.classLevelColorCode }}"{% endif %}>
                            {% if classRoomCell.course is not null %}
                                    <div class="transbox">
                                        <p>
                                        <strong>Niveau {{ classRoomCell.course.classLevelLabel }}</strong>
                                        <br/>
                                        {{ classRoomCell.course.startTime | date('H:i') }} - {{ classRoomCell.course.endTime | date('H:i') }}
                                        <br />
                                        {% for teacher in classRoomCell.course.teachers %}
                                            {{ teacher['teacher_firstName'] }} {{ teacher['teacher_lastName'] }}<br />
                                        {% endfor %}
                                        {% if classRoomCell.course.alternateStartDate is not empty or classRoomCell.course.alternateStartDate is not empty %}
                                            {% set currentSemester = app.session.get('currentSemester') %}
                                            {% if classRoomCell.course.alternateStartDate is not empty %}
                                              à partir du {{ classRoomCell.course.alternateStartDate | date("d/m/Y") }}
                                                <br />
                                            {%endif %}
                                            
                                            {% if classRoomCell.course.alternateEndDate is not empty %}
                                               jusqu'au {{ classRoomCell.course.alternateEndDate | date("d/m/Y") }}
                                                <br />
                                            {%endif %}
                                        {% endif %}
                                        <a href="{{ path('course_show', { 'id': classRoomCell.course.id }) }}">Détail</a>
                                        </p>
                                    </div>
                            {% else %}
                                {{ classRoomCell.content | raw }}
                            {% endif %}
                            </td>
                        {% endif %}
                    {% endfor %}
                {% endfor %}
            </tr>
            {% endfor %}
        </table>
    </div>
</div>
{% endblock %}
Construction:
private function generatePlanning() {
        $semesterId = $this->getSelectedSemesterId();
        
        $courses = $this->getManager()->getAllHydratedCourses($semesterId);
        
        // $organizationBranchId = $this->getSelectedOrganizationBranchId();
        // $classRooms = $this->getEntityManager()->getRepository('VirguleMainBundle:ClassRoom')->getClassRoomsForOrganizationBranch($organizationBranchId);
        
        $planning = new Planning($courses);
        return Array('headerCells' => $planning->getHeader(), 'planningRows' => $planning->getRows());
        
    }
Le planning en l'état construit les colonnes de salles à partir de celles contenues dans les cours passés en paramètres, donc si vous avez une salle qui ne contient aucun cours, elle n'apparaîtra pas, mais ça se change facilement.

Les sources sur GitHub:
https://github.com/glucazeau/Virgule/tr ... y/Planning
https://github.com/glucazeau/Virgule/bl ... .html.twig
Vous n’avez pas les permissions nécessaires pour voir les fichiers joints à ce message.

Petit nouveau ! | 1 Messages

18 avr. 2016, 13:27

ton planning sous forme HTML ne fonctionne pas quand je le met

Petit nouveau ! | 2 Messages

13 mars 2017, 12:45

Bonjour, je déterre un peu le sujet, mais je tente :

J'ai utilisé la 1ère version du planning (besoin d'afficher une seule journée depuis BDD mysql, mais plein de salles/cours), et ça me fait gagner énormément de temps merci !
J'aurai bien aimé inversé les abscisses et ordonnées : à savoir heures en haut, et salles (à la place des jours) sur la gauche.
y'a-t-il un moyen aisé de faire ça (si tu as toujours la logique en tête) ?

Ce que ça donne actuellement :
Image

Petit nouveau ! | 2 Messages

13 mars 2017, 13:19

Voici :

Code : Tout sélectionner

<?php include('Planning.php'); include('PlanningCellule.php'); include('PlanningMapper.php'); $contenusCellules[] = new PlanningCellule(1,'17:15:00','19:00:00','#008000','<b>Zeus</b><br />B1/1'); $contenusCellules[] = new PlanningCellule(1,'19:00:00','21:00:00','#7CCAF4','<b>Ryle</b><br />A2'); $planning = new Planning(1, 6, 540, 1320, 15, $contenusCellules); $planning->afficherHtmlTable(); ?>
Merci,
Fabrice
Sûrement trop tard, mais j'ai modifié pour ma part le PlanningCellule.php comme suit dans la fonction __set :

Code : Tout sélectionner

if ($tabHeure[1] == 15) $value += 0.25; if ($tabHeure[1] == 30) $value += 0.5; if ($tabHeure[1] == 45) $value += 0.75;

Petit nouveau ! | 1 Messages

06 mai 2019, 16:31

Bonjour,
J'utilise régulièrement la version 1 du calendrier par semaine sans chevauchement. Je suis tres interesse par la version 2 qui finalement autorise les chevauchements mais je n'arrive pas à le planning. Je ne connais pas le format TWIG. Auriez-vous un exemple html avec la version 2. Merci beaucoup pour le partage?

Petit nouveau ! | 1 Messages

06 févr. 2024, 16:06

Salut à tous,

Pour ceux qui cherchent à étendre les fonctionnalités du planning, par exemple en affichant sur plusieurs semaines ou en modifiant les heures de début et de fin, vous pourriez envisager d'implémenter une fonctionnalité de pagination pour naviguer entre les semaines. Il serait également utile de rendre les paramètres du planning plus dynamiques, en permettant à l'utilisateur de les configurer via l'interface utilisateur.

Concernant la classe PlanningCellule et les méthodes __get et __set, elles sont des méthodes magiques en PHP qui permettent de gérer l'accès aux propriétés de l'objet. La méthode __set est appelée lorsqu'on écrit des données sur des propriétés inaccessibles ou non existantes, et __get est appelée lors de la lecture de ces mêmes propriétés. Cela peut être utilisé pour contrôler la façon dont les propriétés sont mises à jour ou accédées.