linking demandes
This commit is contained in:
parent
0aa050b38b
commit
7f79ec3a9f
6 changed files with 190 additions and 10 deletions
|
@ -107,6 +107,7 @@ class LinkDemandesPlacesCommand extends Command
|
||||||
|
|
||||||
if (!$dryRun) {
|
if (!$dryRun) {
|
||||||
$demande->setPlace($bestMatch);
|
$demande->setPlace($bestMatch);
|
||||||
|
$demande->setPlaceUuid($bestMatch->getUuidForUrl());
|
||||||
$demande->setStatus('linked_to_place');
|
$demande->setStatus('linked_to_place');
|
||||||
$this->entityManager->persist($demande);
|
$this->entityManager->persist($demande);
|
||||||
$linkedCount++;
|
$linkedCount++;
|
||||||
|
@ -199,4 +200,4 @@ class LinkDemandesPlacesCommand extends Command
|
||||||
{
|
{
|
||||||
return str_replace(['%', '_'], ['\%', '\_'], $str);
|
return str_replace(['%', '_'], ['\%', '\_'], $str);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
116
src/Command/LinkDemandesPlacesOsmCommand.php
Normal file
116
src/Command/LinkDemandesPlacesOsmCommand.php
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Command;
|
||||||
|
|
||||||
|
use App\Entity\Demande;
|
||||||
|
use App\Entity\Place;
|
||||||
|
use App\Repository\DemandeRepository;
|
||||||
|
use App\Repository\PlaceRepository;
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use Symfony\Component\Console\Attribute\AsCommand;
|
||||||
|
use Symfony\Component\Console\Command\Command;
|
||||||
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
|
use Symfony\Component\Console\Input\InputOption;
|
||||||
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||||
|
|
||||||
|
#[AsCommand(
|
||||||
|
name: 'app:link-demandes-places-osm',
|
||||||
|
description: 'Link Demandes to Places based on matching OSM type and ID',
|
||||||
|
)]
|
||||||
|
class LinkDemandesPlacesOsmCommand extends Command
|
||||||
|
{
|
||||||
|
private EntityManagerInterface $entityManager;
|
||||||
|
private DemandeRepository $demandeRepository;
|
||||||
|
private PlaceRepository $placeRepository;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
EntityManagerInterface $entityManager,
|
||||||
|
DemandeRepository $demandeRepository,
|
||||||
|
PlaceRepository $placeRepository
|
||||||
|
) {
|
||||||
|
parent::__construct();
|
||||||
|
$this->entityManager = $entityManager;
|
||||||
|
$this->demandeRepository = $demandeRepository;
|
||||||
|
$this->placeRepository = $placeRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function configure(): void
|
||||||
|
{
|
||||||
|
$this
|
||||||
|
->addOption('dry-run', null, InputOption::VALUE_NONE, 'Show matches without linking');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||||
|
{
|
||||||
|
$io = new SymfonyStyle($input, $output);
|
||||||
|
$io->title('Linking Demandes to Places based on matching OSM type and ID');
|
||||||
|
|
||||||
|
$dryRun = $input->getOption('dry-run');
|
||||||
|
|
||||||
|
// Find all Demandes without a UUID but with OSM type and ID
|
||||||
|
$demandesWithoutUuid = $this->demandeRepository->createQueryBuilder('d')
|
||||||
|
->where('d.placeUuid IS NULL')
|
||||||
|
->andWhere('d.osmObjectType IS NOT NULL')
|
||||||
|
->andWhere('d.osmId IS NOT NULL')
|
||||||
|
->getQuery()
|
||||||
|
->getResult();
|
||||||
|
|
||||||
|
if (empty($demandesWithoutUuid)) {
|
||||||
|
$io->warning('No Demandes without UUID but with OSM type and ID found.');
|
||||||
|
return Command::SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
$io->info(sprintf('Found %d Demandes without UUID but with OSM type and ID.', count($demandesWithoutUuid)));
|
||||||
|
|
||||||
|
// Process each Demande
|
||||||
|
$linkedCount = 0;
|
||||||
|
/** @var Demande $demande */
|
||||||
|
foreach ($demandesWithoutUuid as $demande) {
|
||||||
|
$osmType = $demande->getOsmObjectType();
|
||||||
|
$osmId = $demande->getOsmId();
|
||||||
|
|
||||||
|
// Find Place with matching OSM type and ID
|
||||||
|
$place = $this->placeRepository->findOneBy([
|
||||||
|
'osm_kind' => $osmType,
|
||||||
|
'osmId' => $osmId
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($place) {
|
||||||
|
$io->text(sprintf(
|
||||||
|
'Match found: Demande #%d -> Place #%d (OSM %s/%d)',
|
||||||
|
$demande->getId(),
|
||||||
|
$place->getId(),
|
||||||
|
$osmType,
|
||||||
|
$osmId
|
||||||
|
));
|
||||||
|
|
||||||
|
if (!$dryRun) {
|
||||||
|
$demande->setPlace($place);
|
||||||
|
$demande->setPlaceUuid($place->getUuidForUrl());
|
||||||
|
$demande->setStatus('linked_to_place');
|
||||||
|
$this->entityManager->persist($demande);
|
||||||
|
$linkedCount++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$io->text(sprintf(
|
||||||
|
'No matching Place found for Demande #%d (OSM %s/%d)',
|
||||||
|
$demande->getId(),
|
||||||
|
$osmType,
|
||||||
|
$osmId
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$dryRun && $linkedCount > 0) {
|
||||||
|
$this->entityManager->flush();
|
||||||
|
$io->success(sprintf('Linked %d Demandes to Places based on OSM type and ID.', $linkedCount));
|
||||||
|
} elseif ($dryRun) {
|
||||||
|
$io->info('Dry run completed. No changes were made.');
|
||||||
|
} else {
|
||||||
|
$io->info('No Demandes were linked to Places.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return Command::SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
|
@ -151,6 +151,20 @@ class PublicController extends AbstractController
|
||||||
$demande->setOsmId((int)$data['osmId']);
|
$demande->setOsmId((int)$data['osmId']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if a Place exists with the same OSM ID and type
|
||||||
|
if ($demande->getOsmId() && $demande->getOsmObjectType()) {
|
||||||
|
$existingPlace = $this->entityManager->getRepository(Place::class)->findOneBy([
|
||||||
|
'osm_kind' => $demande->getOsmObjectType(),
|
||||||
|
'osmId' => $demande->getOsmId()
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($existingPlace) {
|
||||||
|
// Link the Place UUID to the Demande
|
||||||
|
$demande->setPlaceUuid($existingPlace->getUuidForUrl());
|
||||||
|
$demande->setPlace($existingPlace);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$this->entityManager->persist($demande);
|
$this->entityManager->persist($demande);
|
||||||
$this->entityManager->flush();
|
$this->entityManager->flush();
|
||||||
|
|
||||||
|
|
|
@ -96,6 +96,7 @@
|
||||||
<th>Email</th>
|
<th>Email</th>
|
||||||
<th>Date de création</th>
|
<th>Date de création</th>
|
||||||
<th>Statut</th>
|
<th>Statut</th>
|
||||||
|
<th>OSM</th>
|
||||||
<th>Place UUID</th>
|
<th>Place UUID</th>
|
||||||
<th>Dernière tentative de contact</th>
|
<th>Dernière tentative de contact</th>
|
||||||
<th>Actions</th>
|
<th>Actions</th>
|
||||||
|
@ -105,7 +106,15 @@
|
||||||
{% for demande in demandes %}
|
{% for demande in demandes %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ demande.id }}</td>
|
<td>{{ demande.id }}</td>
|
||||||
<td>{{ demande.query }}</td>
|
<td>
|
||||||
|
{% if demande.placeUuid and demande.osmObjectType and demande.osmId %}
|
||||||
|
<a href="{{ path('app_public_edit_by_osm', {'osm_kind': demande.osmObjectType, 'osm_id': demande.osmId}) }}" title="Éditer la place">
|
||||||
|
{{ demande.query }}
|
||||||
|
</a>
|
||||||
|
{% else %}
|
||||||
|
{{ demande.query }}
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
<td>{{ demande.email }}</td>
|
<td>{{ demande.email }}</td>
|
||||||
<td>{{ demande.createdAt ? demande.createdAt|date('Y-m-d H:i:s') : '' }}</td>
|
<td>{{ demande.createdAt ? demande.createdAt|date('Y-m-d H:i:s') : '' }}</td>
|
||||||
<td>
|
<td>
|
||||||
|
@ -123,7 +132,28 @@
|
||||||
{{ demande.status }}
|
{{ demande.status }}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td>{{ demande.placeUuid }}</td>
|
<td>
|
||||||
|
{% if demande.osmObjectType and demande.osmId %}
|
||||||
|
<a href="https://www.openstreetmap.org/{{ demande.osmObjectType }}/{{ demande.osmId }}" target="_blank" title="Voir sur OpenStreetMap">
|
||||||
|
<i class="bi bi-globe"></i> {{ demande.osmObjectType }}/{{ demande.osmId }}
|
||||||
|
</a>
|
||||||
|
{% else %}
|
||||||
|
-
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{% if demande.placeUuid %}
|
||||||
|
{% if demande.osmObjectType and demande.osmId %}
|
||||||
|
<a href="{{ path('app_public_edit_by_osm', {'osm_kind': demande.osmObjectType, 'osm_id': demande.osmId}) }}" title="Éditer la place">
|
||||||
|
{{ demande.placeUuid }}
|
||||||
|
</a>
|
||||||
|
{% else %}
|
||||||
|
{{ demande.placeUuid }}
|
||||||
|
{% endif %}
|
||||||
|
{% else %}
|
||||||
|
{{ demande.placeUuid }}
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
<td>{{ demande.lastContactAttempt ? demande.lastContactAttempt|date('Y-m-d H:i:s') : '' }}</td>
|
<td>{{ demande.lastContactAttempt ? demande.lastContactAttempt|date('Y-m-d H:i:s') : '' }}</td>
|
||||||
<td>
|
<td>
|
||||||
<div class="btn-group" role="group">
|
<div class="btn-group" role="group">
|
||||||
|
@ -140,7 +170,7 @@
|
||||||
</tr>
|
</tr>
|
||||||
{% else %}
|
{% else %}
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="8" class="text-center">Aucune demande trouvée</td>
|
<td colspan="9" class="text-center">Aucune demande trouvée</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|
|
@ -508,18 +508,21 @@
|
||||||
|
|
||||||
// Mettre à jour les statistiques
|
// Mettre à jour les statistiques
|
||||||
function updateStats() {
|
function updateStats() {
|
||||||
if (countData.length > 0) {
|
if (Array.isArray(countData) && countData.length > 0) {
|
||||||
const latestCount = countData[countData.length - 1];
|
const latestCount = countData[countData.length - 1];
|
||||||
document.getElementById('currentCount').textContent = latestCount.value;
|
document.getElementById('currentCount').textContent = latestCount.value;
|
||||||
document.getElementById('lastUpdate').textContent = new Date(latestCount.date).toLocaleDateString('fr-FR');
|
document.getElementById('lastUpdate').textContent = new Date(latestCount.date).toLocaleDateString('fr-FR');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (completionData.length > 0) {
|
if (Array.isArray(completionData) && completionData.length > 0) {
|
||||||
const latestCompletion = completionData[completionData.length - 1];
|
const latestCompletion = completionData[completionData.length - 1];
|
||||||
document.getElementById('currentCompletion').textContent = latestCompletion.value + '%';
|
document.getElementById('currentCompletion').textContent = latestCompletion.value + '%';
|
||||||
}
|
}
|
||||||
|
|
||||||
document.getElementById('dataPoints').textContent = Math.max(countData.length, completionData.length);
|
document.getElementById('dataPoints').textContent = Math.max(
|
||||||
|
Array.isArray(countData) ? countData.length : 0,
|
||||||
|
Array.isArray(completionData) ? completionData.length : 0
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configuration commune pour les graphiques
|
// Configuration commune pour les graphiques
|
||||||
|
@ -571,7 +574,7 @@
|
||||||
datasets: [
|
datasets: [
|
||||||
{
|
{
|
||||||
label: "Nombre d'objets",
|
label: "Nombre d'objets",
|
||||||
data: countData?.map(d => ({ x: new Date(d.date), y: d.value })),
|
data: Array.isArray(countData) ? countData.map(d => ({ x: new Date(d.date), y: d.value })) : [],
|
||||||
borderColor: '#0d6efd',
|
borderColor: '#0d6efd',
|
||||||
backgroundColor: 'rgba(13, 110, 253, 0.1)',
|
backgroundColor: 'rgba(13, 110, 253, 0.1)',
|
||||||
borderWidth: 2,
|
borderWidth: 2,
|
||||||
|
@ -581,7 +584,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Pourcentage de complétion',
|
label: 'Pourcentage de complétion',
|
||||||
data: completionData?.map(d => ({ x: new Date(d.date), y: d.value })),
|
data: Array.isArray(completionData) ? completionData.map(d => ({ x: new Date(d.date), y: d.value })) : [],
|
||||||
borderColor: '#198754',
|
borderColor: '#198754',
|
||||||
backgroundColor: 'rgba(25, 135, 84, 0.1)',
|
backgroundColor: 'rgba(25, 135, 84, 0.1)',
|
||||||
borderWidth: 2,
|
borderWidth: 2,
|
||||||
|
|
|
@ -47,6 +47,7 @@
|
||||||
<th>Nom du commerce</th>
|
<th>Nom du commerce</th>
|
||||||
<th>Date de création</th>
|
<th>Date de création</th>
|
||||||
<th>Statut</th>
|
<th>Statut</th>
|
||||||
|
<th>OSM</th>
|
||||||
<th>Dernière tentative de contact</th>
|
<th>Dernière tentative de contact</th>
|
||||||
{% if is_granted('ROLE_ADMIN') %}
|
{% if is_granted('ROLE_ADMIN') %}
|
||||||
<th>Actions</th>
|
<th>Actions</th>
|
||||||
|
@ -74,6 +75,21 @@
|
||||||
{{ demande.status }}
|
{{ demande.status }}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
|
<td>
|
||||||
|
{% if demande.osmObjectType and demande.osmId %}
|
||||||
|
<a href="https://www.openstreetmap.org/{{ demande.osmObjectType }}/{{ demande.osmId }}" target="_blank" title="Voir sur OpenStreetMap">
|
||||||
|
<i class="bi bi-globe"></i> {{ demande.osmObjectType }}/{{ demande.osmId }}
|
||||||
|
</a>
|
||||||
|
{% if demande.placeUuid %}
|
||||||
|
<br>
|
||||||
|
<a href="{{ path('app_public_edit_by_osm', {'osm_kind': demande.osmObjectType, 'osm_id': demande.osmId}) }}" title="Éditer la place">
|
||||||
|
<i class="bi bi-pencil-square"></i> Éditer
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
{% else %}
|
||||||
|
-
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
<td>{{ demande.lastContactAttempt ? demande.lastContactAttempt|date('Y-m-d H:i:s') : '' }}</td>
|
<td>{{ demande.lastContactAttempt ? demande.lastContactAttempt|date('Y-m-d H:i:s') : '' }}</td>
|
||||||
{% if is_granted('ROLE_ADMIN') %}
|
{% if is_granted('ROLE_ADMIN') %}
|
||||||
<td>
|
<td>
|
||||||
|
@ -92,7 +108,7 @@
|
||||||
</tr>
|
</tr>
|
||||||
{% else %}
|
{% else %}
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="{% if is_granted('ROLE_ADMIN') %}6{% else %}5{% endif %}" class="text-center">Aucune demande trouvée pour cette ville</td>
|
<td colspan="{% if is_granted('ROLE_ADMIN') %}7{% else %}6{% endif %}" class="text-center">Aucune demande trouvée pour cette ville</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue