first commit

This commit is contained in:
2025-07-06 16:29:23 +02:00
commit 77160b1905
122 changed files with 18906 additions and 0 deletions

View File

@@ -0,0 +1,139 @@
<?php
namespace App\Service;
class ImageService
{
// Hauteur d'une image
public function getHeight(string $image): int
{
$size = getimagesize($image);
$height = $size[1];
return $height;
}
// Largeur d'une imgage
public function getWidth(string $image): int
{
$size = getimagesize($image);
$width = $size[0];
return $width;
}
public function resizeImage(string $image, int $maxWidth, int $maxHeight): void
{
list($width, $height, $imageType) = getimagesize($image);
$imageType = image_type_to_mime_type($imageType);
// Définir le pourcentage de réduction de l'image
$scale = $maxHeight / $height;
if (($width * $scale) > $maxWidth) {
$scale = $maxWidth / $width;
}
// Création de l'image redimentionnée
$newImageWidth = (int) ceil($width * $scale);
$newImageHeight = (int) ceil($height * $scale);
$newImage = imagecreatetruecolor($newImageWidth, $newImageHeight);
switch ($imageType) {
case 'image/gif':
$source = imagecreatefromgif($image);
break;
case 'image/pjpeg':
case 'image/jpeg':
case 'image/jpg':
$source = imagecreatefromjpeg($image);
break;
case 'image/png':
case 'image/x-png':
$source = imagecreatefrompng($image);
break;
case 'image/webp':
$source = imagecreatefromwebp($image);
break;
default:
$source= imagecreatefromgif($image);
break;
}
imagecopyresampled($newImage, $source, 0, 0, 0, 0, $newImageWidth, $newImageHeight, $width, $height);
switch ($imageType) {
case 'image/gif':
imagegif($newImage, $image);
break;
case 'image/pjpeg':
case 'image/jpeg':
case 'image/jpg':
imagejpeg($newImage, $image, 90);
break;
case 'image/png':
case 'image/x-png':
imagepng($newImage, $image);
break;
case 'image/webp':
imagewebp($newImage, $image, 90);
}
}
public function cropImage(string $image, string $thumb, int $x, int $y, int $cropWidth, int $cropHeight, int $maxWidth, int $maxHeight): void
{
list($width, $height, $imageType) = getimagesize($image);
$imageType = image_type_to_mime_type($imageType);
// Définir le pourcentage de réduction de l'image
$scale = $maxHeight / $cropHeight;
if (($cropWidth * $scale) > $maxWidth) {
$scale = $maxWidth / $cropWidth;
}
// Création de l'image redimentionnée
$newImageWidth = (int) ceil($cropWidth * $scale);
$newImageHeight = (int) ceil($cropHeight * $scale);
$newImage = imagecreatetruecolor($newImageWidth, $newImageHeight);
switch ($imageType) {
case 'image/gif':
$source = imagecreatefromgif($image);
break;
case 'image/pjpeg':
case 'image/jpeg':
case 'image/jpg':
$source = imagecreatefromjpeg($image);
break;
case 'image/png':
case 'image/x-png':
$source = imagecreatefrompng($image);
break;
case 'image/webp':
$source = imagecreatefromwebp($image);
break;
default:
$source= imagecreatefromgif($image);
break;
}
imagecopyresampled($newImage, $source, 0, 0, $x, $y, $newImageWidth, $newImageHeight, $cropWidth, $cropHeight);
switch ($imageType) {
case 'image/gif':
imagegif($newImage, $thumb);
break;
case 'image/pjpeg':
case 'image/jpeg':
case 'image/jpg':
imagejpeg($newImage, $thumb, 90);
break;
case 'image/png':
case 'image/x-png':
imagepng($newImage, $thumb);
break;
case 'image/webp':
imagewebp($newImage, $thumb, 90);
}
}
}

View File

@@ -0,0 +1,298 @@
<?php
namespace App\Service;
use App\Entity\Issue;
use App\Entity\Project;
use App\Repository\IssueRepository;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
class RedmineService
{
private string $baseUrl;
private HttpClientInterface $client;
private IssueRepository $issueRepository;
private EntityManagerInterface $em;
public function __construct(HttpClientInterface $client, ParameterBagInterface $params, IssueRepository $issueRepository, EntityManagerInterface $em)
{
$this->client = $client;
$this->baseUrl = rtrim($params->get('redmineUrl'), '/');
$this->issueRepository = $issueRepository;
$this->em = $em;
}
/**
* Récupère les projets accessibles via l'API key.
*/
public function getProjects(string $apiKey): array
{
try {
$response = $this->client->request('GET', $this->baseUrl.'/projects.json', [
'headers' => [
'X-Redmine-API-Key' => $apiKey,
],
]);
if (200 !== $response->getStatusCode()) {
throw new \RuntimeException('Erreur de communication avec Redmine : '.$response->getStatusCode());
}
$data = $response->toArray();
return $data['projects'] ?? [];
} catch (TransportExceptionInterface $e) {
throw new \RuntimeException('Erreur de communication avec Redmine : '.$e->getMessage());
}
}
public function getProject(int|string $id, string $apiKey): ?array
{
try {
$response = $this->client->request('GET', $this->baseUrl.'/projects/'.$id.'.json?include=trackers,issue_categories,issue_custom_fields', [
'headers' => [
'X-Redmine-API-Key' => $apiKey,
'Accept' => 'application/json',
],
]);
$status = $response->getStatusCode();
if (200 !== $response->getStatusCode()) {
throw new \RuntimeException('Erreur de communication avec Redmine : '.$response->getStatusCode());
}
$data = $response->toArray();
$data['project']['issue_statuses'] = $this->getIssueStatuses($apiKey);
$data['project']['issue_priorities'] = $this->getIssuePriorities($apiKey);
$data['project']['versions'] = $this->getProjectVersions($id, $apiKey);
if (empty($data['project']['versions']) && array_key_exists('parent', $data['project'])) {
$data['project']['versions'] = $this->getProjectSprints($data['project']['parent']['id'], $apiKey);
}
$data['project']['sprints'] = $this->getProjectSprints($id, $apiKey);
if (empty($data['project']['sprints']) && array_key_exists('parent', $data['project'])) {
$data['project']['sprints'] = $this->getProjectSprints($data['project']['parent']['id'], $apiKey);
}
return $data['project'] ?? null;
} catch (TransportExceptionInterface $e) {
throw new \RuntimeException('Erreur de communication avec Redmine : '.$e->getMessage());
}
}
public function getIssueStatuses(string $apiKey): array
{
try {
$response = $this->client->request('GET', $this->baseUrl.'/issue_statuses.json', [
'headers' => [
'X-Redmine-API-Key' => $apiKey,
'Accept' => 'application/json',
],
]);
if (200 !== $response->getStatusCode()) {
throw new \RuntimeException('Erreur de communication avec Redmine : '.$response->getStatusCode());
}
return $response->toArray()['issue_statuses'] ?? [];
} catch (TransportExceptionInterface $e) {
throw new \RuntimeException('Erreur de communication avec Redmine : '.$e->getMessage());
}
}
public function getIssuePriorities(string $apiKey): array
{
try {
$response = $this->client->request('GET', $this->baseUrl.'/enumerations/issue_priorities.json', [
'headers' => [
'X-Redmine-API-Key' => $apiKey,
'Accept' => 'application/json',
],
]);
if (200 !== $response->getStatusCode()) {
throw new \RuntimeException('Erreur de communication avec Redmine : '.$response->getStatusCode());
}
$data = $response->toArray();
return $data['issue_priorities'] ?? [];
} catch (TransportExceptionInterface $e) {
throw new \RuntimeException('Erreur de communication avec Redmine : '.$e->getMessage());
}
}
public function getProjectVersions(int $id, string $apiKey): array
{
try {
$response = $this->client->request('GET', $this->baseUrl.'/projects/'.$id.'/versions.json', [
'headers' => [
'X-Redmine-API-Key' => $apiKey,
'Accept' => 'application/json',
],
]);
if (200 !== $response->getStatusCode()) {
throw new \RuntimeException('Erreur de communication avec Redmine : '.$response->getStatusCode());
}
$data = $response->toArray();
return $data['versions'];
} catch (TransportExceptionInterface $e) {
throw new \RuntimeException('Erreur de communication avec Redmine : '.$e->getMessage());
}
}
public function getProjectSprints(int $projectId, string $apiKey): array
{
try {
$url = "{$this->baseUrl}/projects/{$projectId}/agile_sprints.json";
$response = $this->client->request('GET', $url, [
'headers' => [
'X-Redmine-API-Key' => $apiKey,
'Accept' => 'application/json',
],
]);
if (200 !== $response->getStatusCode()) {
throw new \RuntimeException('Erreur de communication avec Redmine : '.$response->getStatusCode());
}
$data = $response->toArray();
return $data['sprints'] ?? [];
} catch (TransportExceptionInterface $e) {
throw new \RuntimeException('Erreur de communication avec Redmine : '.$e->getMessage());
}
}
public function majProjectIssues(Project $project, string $apiKey, bool $force = false)
{
$rissues = $this->getProjectIssues($project->getId(), $apiKey, $force ? null : $project->getUpdateAt());
foreach ($rissues as $rissue) {
$issue = $this->issueRepository->find($rissue['id']);
if (!$issue) {
$issue = new Issue();
$issue->setId($rissue['id']);
}
$issue->setRedmine($rissue);
$issue->setProject($project);
// Calcul de la position du status
$issueStatusId = $rissue['status']['id'];
$statusPosition = 0;
foreach ($project->getRedmine()['issue_statuses'] as $index => $status) {
if ($status['id'] === $issueStatusId) {
$statusPosition = $index; // ou $index + 1 si tu veux position humaine
break;
}
}
$issue->setRowstatus($statusPosition);
// Calcul de la position version
if (isset($rissue['fixed_version'])) {
$issue->setRowversion($rissue['fixed_version']['name']);
} else {
$issue->setRowversion('');
}
// Calcul de la position sprint
$issueSprintId = $rissue['sprint']['agile_sprint_id'];
$sprintPosition = '';
foreach ($project->getRedmine()['sprints'] as $sprint) {
if ($sprint['id'] === $issueSprintId) {
$sprintPosition = $sprint['id']; // ou $index + 1 si tu veux position humaine
break;
}
}
$issue->setRowsprint($sprintPosition);
// Calcul position issue
if (isset($rissue['sprint'])) {
$issue->setRowissue($rissue['sprint']['position'] ?? 1000000);
} else {
$issue->setRowissue(1000000);
}
$this->em->persist($issue);
$project->setUpdateAt(new \DateTime());
$this->em->flush();
}
}
public function getProjectIssues(int $projectId, string $apiKey, ?\DateTimeInterface $updatedSince = null): array
{
$limit = 100;
$offset = 0;
$allIssues = [];
do {
$queryParams = [
'project_id' => $projectId,
'limit' => $limit,
'offset' => $offset,
'status_id' => '*', // Inclure toutes les issues
];
if (null !== $updatedSince) {
$queryParams['updated_on'] = $updatedSince->format('Y-m-d\TH:i:s\Z');
}
$url = $this->baseUrl.'/issues.json?'.http_build_query($queryParams);
$response = $this->client->request('GET', $url, [
'headers' => [
'X-Redmine-API-Key' => $apiKey,
],
]);
if (200 !== $response->getStatusCode()) {
throw new \RuntimeException('Erreur API Redmine : '.$response->getStatusCode());
}
$data = $response->toArray();
$issues = $data['issues'] ?? [];
foreach ($issues as $key => $issue) {
$issues[$key]['sprint'] = $this->getIssueAgile($issue['id'], $apiKey);
}
$allIssues = array_merge($allIssues, $issues);
$offset += $limit;
$totalCount = $data['total_count'] ?? 0;
} while ($offset < $totalCount);
return $allIssues;
}
public function getIssueAgile(int $issueId, string $apiKey): array
{
try {
$url = "{$this->baseUrl}/issues/{$issueId}/agile_data.json";
$response = $this->client->request('GET', $url, [
'headers' => [
'X-Redmine-API-Key' => $apiKey,
'Accept' => 'application/json',
],
]);
dump($response);
if (200 !== $response->getStatusCode()) {
throw new \RuntimeException('Erreur de communication avec Redmine : '.$response->getStatusCode());
}
$data = $response->toArray();
return $data['agile_data'] ?? [];
} catch (TransportExceptionInterface $e) {
throw new \RuntimeException('Erreur de communication avec Redmine : '.$e->getMessage());
}
}
}