Browse Source

Ajoute l’outil Osmose

master
vincent 1 week ago
parent
commit
1fb4eb9cf7
13 changed files with 244 additions and 3 deletions
  1. +1
    -0
      assets/app.js
  2. +2
    -1
      assets/controllers/map_controller.js
  3. +2
    -0
      config/packages/twig.yaml
  4. +7
    -0
      importmap.php
  5. +19
    -0
      lib/OSM/Element/Element.php
  6. +25
    -0
      lib/OSM/Element/Node.php
  7. +20
    -0
      lib/OSM/OSM.php
  8. +0
    -1
      php.ini
  9. +1
    -1
      src/Controller/TaskController.php
  10. +121
    -0
      src/Controller/ToolsController.php
  11. +25
    -0
      src/Form/OsmoseToolType.php
  12. +16
    -0
      src/Service/OsmoseClient.php
  13. +5
    -0
      templates/tools/osmose.html.twig

+ 1
- 0
assets/app.js View File

@ -1,6 +1,7 @@
import './bootstrap.js'; // Stimulus
import './vendor/bootstrap/dist/css/bootstrap.min.css'; // Bootstrap
import './vendor/leaflet.markercluster/dist/MarkerCluster.min.css'; // Leaflet clusters
import './vendor/leaflet/dist/leaflet.min.css'; // Leaflet
import './styles/app.css'; // Nos personnalisations


+ 2
- 1
assets/controllers/map_controller.js View File

@ -9,6 +9,7 @@ Cf <https://leafletjs.com/reference.html>
**/
import { Controller } from '@hotwired/stimulus';
import 'leaflet';
import 'leaflet.markercluster';
export default class extends Controller {
static targets = [ 'openLink' ];
@ -57,7 +58,7 @@ export default class extends Controller {
var layer = L.featureGroup();
// Crée la couche dédiée à Overpass
var overpassLayer = L.featureGroup();
var overpassLayer = L.markerClusterGroup();
if (this.overpassResultValue !== '') {
geojsons = JSON.parse(this.overpassResultValue);
if (geojsons.elements.length > 0) {


+ 2
- 0
config/packages/twig.yaml View File

@ -19,6 +19,8 @@ twig:
tools:
- label: 'Communes'
route: 'app_tools_city'
- label: 'Osmose'
route: 'app_tools_osmose'
when@test:
twig:


+ 7
- 0
importmap.php View File

@ -39,4 +39,11 @@ return [
'@symfony/stimulus-bundle' => [
'path' => './vendor/symfony/stimulus-bundle/assets/dist/loader.js',
],
'leaflet.markercluster' => [
'version' => '1.5.3',
],
'leaflet.markercluster/dist/MarkerCluster.min.css' => [
'version' => '1.5.3',
'type' => 'css',
],
];

+ 19
- 0
lib/OSM/Element/Element.php View File

@ -69,4 +69,23 @@ class Element
return $tag->value;
}
public function asDOMElement(\DOMDocument $document): \DOMElement {
$reflect = new \ReflectionClass(get_called_class());
$name = strtolower($reflect->getShortName());
$xml = $document->createElement($name);
$xml->setAttribute('id', $this->id);
$xml->setAttribute('visible', 'true');
foreach ($this->tags as $tag) {
$tagElement = $document->createElement('tag');
$tagElement->setAttribute('k', $tag->key);
$tagElement->setAttribute('v', $tag->value);
$xml->appendChild($tagElement);
}
return $xml;
}
}

+ 25
- 0
lib/OSM/Element/Node.php View File

@ -0,0 +1,25 @@
<?php
namespace OSM\Element;
use OSM\Point;
class Node extends Element
{
public Point $point;
public function completeFromArray(array $array): static
{
$this->point = Point::createFromArray($array);
return $this;
}
public function asDOMElement(\DOMDocument $document): \DOMElement {
$xml = parent::asDOMElement($document);
$xml->setAttribute('lat', $this->point->latitude);
$xml->setAttribute('lon', $this->point->longitude);
return $xml;
}
}

+ 20
- 0
lib/OSM/OSM.php View File

@ -12,6 +12,11 @@ class OSM
{
$array = json_decode($json, true);
return self::createFromArray($array);
}
public static function createFromArray($array)
{
$instance = new self();
$items = $array['elements'];
@ -22,4 +27,19 @@ class OSM
return $instance;
}
public function __toString() {
$document = new \DOMDocument('1.0', 'UTF-8');
$osm = $document->createElement('osm');
$osm->setAttribute('version', '0.6');
foreach ($this->elements as $element) {
$osm->appendChild($element->asDOMElement($document));
}
$document->appendChild($osm);
return $document->saveXML();
}
}

+ 0
- 1
php.ini View File

@ -1,4 +1,3 @@
upload_max_filesize = 40M
post_max_size = 40M
memory_limit = 512M

+ 1
- 1
src/Controller/TaskController.php View File

@ -389,7 +389,7 @@ class TaskController extends AbstractController
// Renvoie le XML OSM associé à la tâche
#[Route('/download/{slug}.osm', name: 'app_task_osm')]
#[IsGranted('ROLE_USER')]
#[IsGranted('PUBLIC_ACCESS')]
public function osm(Request $request, EntityManagerInterface $entityManager, $slug): Response
{
$repository = $entityManager->getRepository(Task::class);


+ 121
- 0
src/Controller/ToolsController.php View File

@ -3,6 +3,8 @@
namespace App\Controller;
use App\Form\CityToolType;
use App\Form\OsmoseToolType;
use App\Service\OsmoseClient;
use App\Service\OverpassClient;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
@ -89,4 +91,123 @@ class ToolsController extends AbstractController
'form' => $form,
]);
}
#[Route('/osmose', name: 'app_tools_osmose')]
public function osmose(
Request $request,
OsmoseClient $osmose,
): Response {
$form = $this->createForm(OsmoseToolType::class, $request->query->all());
$form->add('submit', SubmitType::class, ['label' => 'Générer']);
$form->handleRequest($request);
if ($form->isSubmitted() and $form->isValid()) {
$issues = $osmose->issues([
'item' => $form->get('item')->getData(),
'source' => $form->get('source')->getData(),
'class' => $form->get('class')->getData(),
'username' => '',
'bbox' => '',
'full' => 'true',
'limit' => 500,
]);
$response = new StreamedResponse();
$response->headers->set('Content-Type', 'text/csv');
$response->headers->set(
'Content-Disposition',
HeaderUtils::makeDisposition(
HeaderUtils::DISPOSITION_ATTACHMENT,
'issues.csv'
)
);
$features = json_decode($issues, true)['features'];
$response->setCallback(function () use ($features): void {
$headings = [
'name',
'description',
'osm',
'geojson',
'status',
];
$csv = fopen('php://output', 'a');
fputcsv($csv, $headings);
$total = count($features);
foreach ($features as $index => $feature) {
$name = sprintf('%s n°%d/%d', $feature['properties']['title'], $index + 1, $total);
$description = <<<EOT
### Issue {$feature['properties']['uuid']}
* Level {$feature['properties']['level']}
* Item {$feature['properties']['item']}
* Identifiant de source {$feature['properties']['source_id']}
* Identifiant de classe {$feature['properties']['class']}
### Osmose
[ Fait](https://osmose.openstreetmap.fr/api/0.3/issue/{$feature['properties']['uuid']}/done)
[ Faux positif](https://osmose.openstreetmap.fr/api/0.3/issue/{$feature['properties']['uuid']}/false)
EOT;
if (isset($feature['properties']['fixes'])) {
$tags = [];
foreach ($feature['properties']['fixes'] as $fixItems) {
foreach ($fixItems as $fixItem) {
$isExpected = (
('N' === $fixItem['type'])
and array_key_exists('create', $fixItem)
);
if (!$isExpected) {
continue;
} // TODO gérer tous les cas possibles ici
foreach ($fixItem['create'] as $k => $v) {
$tags[$k] = $v;
}
}
}
$osm = \OSM\OSM::createFromArray([
'elements' => [[
'type' => 'node',
'id' => -1,
'lat' => (float) $feature['geometry']['coordinates'][1],
'lon' => (float) $feature['geometry']['coordinates'][0],
'tags' => $tags,
]],
]);
} else {
$osm = '';
}
$geojson = json_encode([
'type' => 'FeatureCollection',
'features' => [
$feature,
],
]);
fputcsv($csv, [
$name,
$description,
$osm,
$geojson,
'todo',
]);
}
fclose($csv);
});
return $response;
}
return $this->render('tools/osmose.html.twig', [
'form' => $form,
]);
}
}

+ 25
- 0
src/Form/OsmoseToolType.php View File

@ -0,0 +1,25 @@
<?php
namespace App\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\IntegerType;
use Symfony\Component\Form\FormBuilderInterface;
class OsmoseToolType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('item', IntegerType::class, [
'label' => 'Item',
])
->add('source', IntegerType::class, [
'label' => 'Identifiant source',
])
->add('class', IntegerType::class, [
'label' => 'Identifiant de la classe',
])
;
}
}

+ 16
- 0
src/Service/OsmoseClient.php View File

@ -28,4 +28,20 @@ class OsmoseClient
private HttpClientInterface $client,
) {
}
public function issues($params)
{
$response = $this->client->request('GET', 'https://osmose.openstreetmap.fr/api/0.3/issues.geojson', [
'query' => $params,
]);
$isStatusCodeOk = (200 === $response->getStatusCode());
$isContentTypeJson = ('application/vnd.geo+json' === $response->getHeaders()['content-type'][0]);
if (!$isStatusCodeOk or !$isContentTypeJson) {
throw new \RuntimeException('Erreur de communication avec Osmose');
}
return $response->getContent();
}
}

+ 5
- 0
templates/tools/osmose.html.twig View File

@ -0,0 +1,5 @@
{% extends 'tools/base.html.twig' %}
{% block tools_content %}
{{ form(form) }}
{% endblock %}

Loading…
Cancel
Save