This commit is contained in:
2025-07-25 16:09:36 +02:00
parent 4b9a099550
commit fd00af0780
10 changed files with 348 additions and 26 deletions

View File

@ -0,0 +1,104 @@
<?php
namespace App\Controller;
use App\Entity\Project;
use App\Entity\Label;
use App\Form\LabelType;
use App\Repository\LabelRepository;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
class LabelController extends AbstractController
{
#[Route('/admin/label', name: 'app_admin_label')]
public function list(LabelRepository $labelRepository): Response
{
$labels = $labelRepository->findAll();
return $this->render('label/list.html.twig', [
'usemenu' => true,
'usesidebar' => true,
'title' => 'Liste des Labels',
'routesubmit' => 'app_admin_label_submit',
'routeupdate' => 'app_admin_label_update',
'labels' => $labels,
]);
}
#[Route('/admin/label/submit', name: 'app_admin_label_submit')]
public function submit(Request $request, EntityManagerInterface $em): Response
{
$label = new Label();
$form = $this->createForm(LabelType::class, $label, ['mode' => 'submit']);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em->persist($label);
$em->flush();
return $this->redirectToRoute('app_admin_label');
}
return $this->render('label/edit.html.twig', [
'usemenu' => true,
'usesidebar' => true,
'title' => 'Création Label',
'routecancel' => 'app_admin_label',
'routedelete' => 'app_admin_label_delete',
'mode' => 'submit',
'form' => $form,
]);
}
#[Route('/admin/label/update/{id}', name: 'app_admin_label_update')]
public function update(int $id, Request $request, EntityManagerInterface $em): Response
{
$label = $em->getRepository(Label::class)->find($id);
if (!$label) {
return $this->redirectToRoute('app_admin_label');
}
$form = $this->createForm(LabelType::class, $label, ['mode' => 'update']);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em->flush();
return $this->redirectToRoute('app_admin_label');
}
return $this->render('label/edit.html.twig', [
'usemenu' => true,
'usesidebar' => true,
'title' => 'Modification Label = '.$label->getLabelRedmine(),
'routecancel' => 'app_admin_label',
'routedelete' => 'app_admin_label_delete',
'mode' => 'update',
'form' => $form,
]);
}
#[Route('/admin/label/delete/{id}', name: 'app_admin_label_delete')]
public function delete(int $id, EntityManagerInterface $em): Response
{
$label = $em->getRepository(Label::class)->find($id);
if (!$label) {
return $this->redirectToRoute('app_admin_label');
}
// Tentative de suppression
try {
$em->remove($label);
$em->flush();
} catch (\Exception $e) {
$this->addflash('error', $e->getMessage());
return $this->redirectToRoute('app_admin_label_update', ['id' => $id]);
}
return $this->redirectToRoute('app_admin_label');
}
}

51
src/Entity/Label.php Normal file
View File

@ -0,0 +1,51 @@
<?php
namespace App\Entity;
use App\Repository\LabelRepository;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity(repositoryClass: LabelRepository::class)]
#[ORM\Table(name: 'label')]
class Label
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column(type: 'integer')]
private ?int $id = null;
#[ORM\Column(type: 'string', length: 255, nullable: false)]
private string $labelRedmine;
#[ORM\Column(type: 'string', length: 255, nullable: false)]
private string $labelNinemine;
// Getters & Setters
public function getId(): ?int
{
return $this->id;
}
public function getLabelRedmine(): string
{
return $this->labelRedmine;
}
public function setLabelRedmine(string $labelRedmine): self
{
$this->labelRedmine = $labelRedmine;
return $this;
}
public function getLabelNinemine(): string
{
return $this->labelNinemine;
}
public function setLabelNinemine(string $labelNinemine): self
{
$this->labelNinemine = $labelNinemine;
return $this;
}
}

47
src/Form/LabelType.php Normal file
View File

@ -0,0 +1,47 @@
<?php
namespace App\Form;
use App\Entity\Project;
use App\Entity\Label;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use Symfony\Component\Form\Extension\Core\Type\RepeatedType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints\Regex;
class LabelType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('submit', SubmitType::class, [
'label' => 'Valider',
'attr' => ['class' => 'btn btn-success no-print'],
])
->add('labelRedmine', TextType::class, [
'label' => 'Label Redmine',
])
->add('labelNinemine', TextType::class, [
'label' => 'Label Ninemine',
'required' => false,
]);
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => Label::class,
'mode' => 'submit',
]);
}
}

View File

@ -0,0 +1,18 @@
<?php
namespace App\Repository;
use App\Entity\Label;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @extends ServiceEntityRepository<Label>
*/
class LabelRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, Label::class);
}
}

View File

@ -15,29 +15,4 @@ class ProjectRepository extends ServiceEntityRepository
{
parent::__construct($registry, Project::class);
}
// /**
// * @return Project[] Returns an array of Project objects
// */
// public function findByExampleField($value): array
// {
// return $this->createQueryBuilder('c')
// ->andWhere('c.exampleField = :val')
// ->setParameter('val', $value)
// ->orderBy('c.id', 'ASC')
// ->setMaxResults(10)
// ->getQuery()
// ->getResult()
// ;
// }
// public function findOneBySomeField($value): ?Project
// {
// return $this->createQueryBuilder('c')
// ->andWhere('c.exampleField = :val')
// ->setParameter('val', $value)
// ->getQuery()
// ->getOneOrNullResult()
// ;
// }
}

View File

@ -0,0 +1,39 @@
<?php
namespace App\Twig;
use App\Repository\LabelRepository;
use Twig\Extension\AbstractExtension;
use Twig\TwigFunction;
class LabelExtension extends AbstractExtension
{
private LabelRepository $labelRepository;
private array $cache = [];
public function __construct(LabelRepository $labelRepository)
{
$this->labelRepository = $labelRepository;
}
public function getFunctions(): array
{
return [
new TwigFunction('label', [$this, 'label']),
];
}
public function label(string $labelRedmine): string
{
if (isset($this->cache[$labelRedmine])) {
return $this->cache[$labelRedmine];
}
$entity = $this->labelRepository->findOneByLabelRedmine($labelRedmine);
$result = $entity ? $entity->getLabelNinemine() : $labelRedmine;
$this->cache[$labelRedmine] = $result;
return $result;
}
}

View File

@ -96,6 +96,11 @@
<i class="fas fa-building fa-fw"></i>
<span>Projets</span>
</a>
<a href="{{ path('app_admin_label') }}" title="Labels">
<i class="fas fa-puzzle-piece fa-fw"></i>
<span>Labels</span>
</a>
</div>
</sidebar>
{% endif %}

View File

@ -0,0 +1,37 @@
{% extends 'base.html.twig' %}
{% block title %} = {{title}}{% endblock %}
{% block body %}
<h1>{{title}}</h1>
{{ form_start(form) }}
{{ form_widget(form.submit) }}
<a href="{{ path(routecancel) }}" class="btn btn-secondary ms-1">Annuler</a>
{%if mode=="update" %}<a href="{{ path(routedelete,{id:form.vars.value.id}) }}" class="btn btn-danger float-end" onclick="return confirm('Confirmez-vous la suppression de cet enregistrement ?')">Supprimer</a>{%endif%}
{% include('include/error.html.twig') %}
<div class="row">
<div class="col-md-6 mx-auto">
<div class="card mt-3">
<div class="card-header">Information</div>
<div class="card-body">
{{ form_row(form.labelRedmine) }}
{{ form_row(form.labelNinemine) }}
</div>
</div>
</div>
</div>
{{ form_end(form) }}
{% endblock %}
{% block localscript %}
<script>
$(document).ready(function() {
$("#user_username").focus();
});
</script>
{% endblock %}

View File

@ -0,0 +1,42 @@
{% extends 'base.html.twig' %}
{% block title %} = {{title}}{% endblock %}
{% block body %}
<h1>{{title}}</h1>
<a href="{{ path(routesubmit) }}" class="btn btn-success">Ajouter</a>
<div class="dataTable_wrapper">
<table class="table table-striped table-bordered table-hover" id="dataTables" style="width:100%">
<thead>
<tr>
<th width="70px" class="no-sort">Action</th>
<th class="no-sort">Label Redmine</th>
<th>Label Ninemine</th>
</tr>
</thead>
<tbody>
{% for label in labels %}
<tr>
<td><a href="{{ path(routeupdate,{id:label.id}) }}"><i class="fas fa-file fa-2x"></i></a></td>
<td>{{label.labelRedmine}}</td>
<td>{{label.labelNinemine}}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endblock %}
{% block localscript %}
<script>
$(document).ready(function() {
$('#dataTables').DataTable({
columnDefs: [ { "targets": "no-sort", "orderable": false }, { "targets": "no-string", "type" : "num" } ],
responsive: true,
iDisplayLength: 100,
order: [[ 2, "asc" ]]
});
});
</script>
{% endblock %}

View File

@ -263,7 +263,11 @@
{% for status in project.redmine.issue_statuses %}
{% if status.id not in project.hiddenstatuses %}
<div class='statusCard statusCard{{status.id}}'>
<h2>{{ status.name }}</h2>
<h2>
{% set label= label(status.name) %}
{{ label}}
<br><small>{{ label != status.name ? status.name : '&nbsp;' }}</small>
</h2>
{% for sprint in project.redmine.sprints|reverse %}
{% if sprint.id not in project.hiddensprints %}