service motocultrice, traductions

This commit is contained in:
Tykayn 2025-05-26 11:55:44 +02:00 committed by tykayn
parent 528ebb672a
commit f5ab0c8205
16 changed files with 427 additions and 128 deletions

View file

@ -21,6 +21,6 @@ déployer sur un serveur ayant du php 8
créer un utilisateur et sa base
sudo -u postgres psql -c "CREATE USER sf WITH PASSWORD 'jkazhreiidfsDFgfgsgFHGSshdffdshefJYIyl';"
sudo -u postgres psql -c "CREATE USER sf WITH PASSWORD 'sfrgdHYJi56631lyshFSQGfd45452ùwdf54f8fg5dfhg5_tyfdgthIOPHFUGH';"
sudo -u postgres psql -c "CREATE DATABASE \"osm-my-commerce\" OWNER sf;"

View file

@ -14,6 +14,8 @@
"doctrine/doctrine-migrations-bundle": "^3.4",
"doctrine/orm": "^3.1",
"guzzlehttp/guzzle": "^7.9",
"nyholm/psr7": "^1.8",
"php-http/discovery": "^1.20",
"phpdocumentor/reflection-docblock": "^5.6",
"phpstan/phpdoc-parser": "^2.1",
"symfony/asset": "*",

159
composer.lock generated
View file

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "f7625b2c7b49fdb113072ea857ae3f03",
"content-hash": "2ac1e47a82b3110fe5fa1449fc6ad0c5",
"packages": [
{
"name": "doctrine/collections",
@ -1620,6 +1620,163 @@
],
"time": "2025-03-24T10:02:05+00:00"
},
{
"name": "nyholm/psr7",
"version": "1.8.2",
"source": {
"type": "git",
"url": "https://github.com/Nyholm/psr7.git",
"reference": "a71f2b11690f4b24d099d6b16690a90ae14fc6f3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Nyholm/psr7/zipball/a71f2b11690f4b24d099d6b16690a90ae14fc6f3",
"reference": "a71f2b11690f4b24d099d6b16690a90ae14fc6f3",
"shasum": ""
},
"require": {
"php": ">=7.2",
"psr/http-factory": "^1.0",
"psr/http-message": "^1.1 || ^2.0"
},
"provide": {
"php-http/message-factory-implementation": "1.0",
"psr/http-factory-implementation": "1.0",
"psr/http-message-implementation": "1.0"
},
"require-dev": {
"http-interop/http-factory-tests": "^0.9",
"php-http/message-factory": "^1.0",
"php-http/psr7-integration-tests": "^1.0",
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.4",
"symfony/error-handler": "^4.4"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.8-dev"
}
},
"autoload": {
"psr-4": {
"Nyholm\\Psr7\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Tobias Nyholm",
"email": "tobias.nyholm@gmail.com"
},
{
"name": "Martijn van der Ven",
"email": "martijn@vanderven.se"
}
],
"description": "A fast PHP7 implementation of PSR-7",
"homepage": "https://tnyholm.se",
"keywords": [
"psr-17",
"psr-7"
],
"support": {
"issues": "https://github.com/Nyholm/psr7/issues",
"source": "https://github.com/Nyholm/psr7/tree/1.8.2"
},
"funding": [
{
"url": "https://github.com/Zegnat",
"type": "github"
},
{
"url": "https://github.com/nyholm",
"type": "github"
}
],
"time": "2024-09-09T07:06:30+00:00"
},
{
"name": "php-http/discovery",
"version": "1.20.0",
"source": {
"type": "git",
"url": "https://github.com/php-http/discovery.git",
"reference": "82fe4c73ef3363caed49ff8dd1539ba06044910d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-http/discovery/zipball/82fe4c73ef3363caed49ff8dd1539ba06044910d",
"reference": "82fe4c73ef3363caed49ff8dd1539ba06044910d",
"shasum": ""
},
"require": {
"composer-plugin-api": "^1.0|^2.0",
"php": "^7.1 || ^8.0"
},
"conflict": {
"nyholm/psr7": "<1.0",
"zendframework/zend-diactoros": "*"
},
"provide": {
"php-http/async-client-implementation": "*",
"php-http/client-implementation": "*",
"psr/http-client-implementation": "*",
"psr/http-factory-implementation": "*",
"psr/http-message-implementation": "*"
},
"require-dev": {
"composer/composer": "^1.0.2|^2.0",
"graham-campbell/phpspec-skip-example-extension": "^5.0",
"php-http/httplug": "^1.0 || ^2.0",
"php-http/message-factory": "^1.0",
"phpspec/phpspec": "^5.1 || ^6.1 || ^7.3",
"sebastian/comparator": "^3.0.5 || ^4.0.8",
"symfony/phpunit-bridge": "^6.4.4 || ^7.0.1"
},
"type": "composer-plugin",
"extra": {
"class": "Http\\Discovery\\Composer\\Plugin",
"plugin-optional": true
},
"autoload": {
"psr-4": {
"Http\\Discovery\\": "src/"
},
"exclude-from-classmap": [
"src/Composer/Plugin.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Márk Sági-Kazár",
"email": "mark.sagikazar@gmail.com"
}
],
"description": "Finds and installs PSR-7, PSR-17, PSR-18 and HTTPlug implementations",
"homepage": "http://php-http.org",
"keywords": [
"adapter",
"client",
"discovery",
"factory",
"http",
"message",
"psr17",
"psr7"
],
"support": {
"issues": "https://github.com/php-http/discovery/issues",
"source": "https://github.com/php-http/discovery/tree/1.20.0"
},
"time": "2024-10-02T11:20:13+00:00"
},
{
"name": "phpdocumentor/reflection-common",
"version": "2.2.0",

View file

@ -6,6 +6,9 @@ framework:
handle_all_throwables: true
default_locale: 'fr'
translator:
default_path: '%kernel.project_dir%/translations'
fallbacks: ['fr']
# Enables session support. Note that the session will ONLY be started if you read or write from it.
# Remove or comment this section to explicitly disable session support.

View file

@ -0,0 +1,10 @@
services:
Psr\Http\Message\RequestFactoryInterface: '@http_discovery.psr17_factory'
Psr\Http\Message\ResponseFactoryInterface: '@http_discovery.psr17_factory'
Psr\Http\Message\ServerRequestFactoryInterface: '@http_discovery.psr17_factory'
Psr\Http\Message\StreamFactoryInterface: '@http_discovery.psr17_factory'
Psr\Http\Message\UploadedFileFactoryInterface: '@http_discovery.psr17_factory'
Psr\Http\Message\UriFactoryInterface: '@http_discovery.psr17_factory'
http_discovery.psr17_factory:
class: Http\Discovery\Psr17Factory

View file

@ -21,4 +21,7 @@ services:
- '../src/Kernel.php'
# add more service definitions when explicit configuration is needed
GuzzleHttp\Client:
class: GuzzleHttp\Client
# please note that last definitions always *replace* previous ones

View file

@ -0,0 +1,18 @@
<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
final class AdminController extends AbstractController
{
#[Route('/admin', name: 'app_admin')]
public function index(): Response
{
return $this->render('admin/index.html.twig', [
'controller_name' => 'AdminController',
]);
}
}

View file

@ -4,6 +4,7 @@ namespace App\Controller;
use App\Entity\Stats;
use App\Entity\Place;
use App\Service\Motocultrice;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
@ -17,78 +18,17 @@ class PublicController extends AbstractController
private $maptiler_token = 'BVM2NRJuzQunWvXbTnzg';
public function __construct(
private EntityManagerInterface $entityManager
private EntityManagerInterface $entityManager,
private Motocultrice $motocultrice
) {
}
public function get_osm_object_data($osm_object_id = 12855459190)
{
// TODO extraire ceci dans un service
$object_id = "https://www.openstreetmap.org/api/0.6/node/".$osm_object_id;
$osm_object_data = [
// "version"=> "0.6",
// "generator"=> "openstreetmap-cgimap 2.0.1 (2557185 spike-08.openstreetmap.org)",
// "copyright"=> "OpenStreetMap and contributors",
// "attribution"=> "http://www.openstreetmap.org/copyright",
// "license"=> "http://opendatacommons.org/licenses/odbl/1-0/",
// "elements"=> [
// [
// "type"=> "node",
// "id"=> 12855459190,
// "lat"=> 49.6504926,
// "lon"=> -1.5722526,
// "timestamp"=> "2025-05-22T13:15:45Z",
// "version"=> 1,
// "changeset"=> 166613142,
// "user"=> "tykayn",
// "uid"=> 2962129,
// "tags"=> [
// "name"=> "Harry le potier",
// "tourism"=> "artwork"
// ]
// ]
// ]
];
// Récupérer les vraies données OSM
$client = new Client();
try {
$response = $client->get($object_id);
$xml = simplexml_load_string($response->getBody()->getContents());
$json = json_encode($xml);
$osm_object_data = json_decode($json, true);
} catch (\Exception $e) {
// En cas d'erreur, on garde les données de test
$this->addFlash('warning', 'Impossible de récupérer les données OSM. Utilisation des données de test.');
}
// var_dump($osm_object_data['node']);
// die();
// convertir les tags en clés et valeurs
$osm_object_data['tags_converted'] = [];
// var_dump($osm_object_data['node']['tag']);
foreach ($osm_object_data['node']['tag'] as $attribute) {
// var_dump($attribute['@attributes']['k']);
// die();
$osm_object_data['node']['tags_converted'][$attribute['@attributes']['k']] = $attribute['@attributes']['v'];
}
// var_dump($osm_object_data['node']['tags_converted']);
// die();
return $osm_object_data['node'];
}
#[Route('/', name: 'app_public_index')]
public function index(): Response
{
$commerce = $this->get_osm_object_data();
$commerce = $this->motocultrice->get_osm_object_data();
return $this->render('public/index.html.twig', [
'controller_name' => 'PublicController',
'commerce' => $commerce,
@ -212,7 +152,7 @@ class PublicController extends AbstractController
}
// après envoi on récupère les données
$commerce = $this->get_osm_object_data($osm_object_id);
$commerce = $this->motocultrice->get_osm_object_data($osm_object_id);
return $this->render('public/view.html.twig', [
'controller_name' => 'PublicController',
'commerce' => $commerce,

View file

@ -0,0 +1,91 @@
<?php
namespace App\Service;
use Symfony\Contracts\HttpClient\HttpClientInterface;
class Motocultrice
{
private $overpassApiUrl = 'https://overpass-api.de/api/interpreter';
public function __construct(
private HttpClientInterface $client
) {
}
public function labourer(string $zone): array
{
$query = <<<QUERY
[out:json][timeout:25];
area["name"="{$zone}"]->.searchArea;
(
nwr["shop"](area.searchArea);
);
out body;
>;
out skel qt;
QUERY;
try {
$response = $this->client->request('POST', $this->overpassApiUrl, [
'body' => ['data' => $query]
]);
$data = json_decode($response->getContent(), true);
$shops = [];
if (isset($data['elements'])) {
foreach ($data['elements'] as $element) {
if (isset($element['tags']['shop'])) {
$shops[] = [
'id' => $element['id'],
'type' => $element['type'],
'name' => $element['tags']['name'] ?? 'Sans nom',
'shop_type' => $element['tags']['shop'],
'lat' => $element['lat'] ?? null,
'lon' => $element['lon'] ?? null,
'tags' => $element['tags']
];
}
}
}
return $shops;
} catch (\Exception $e) {
throw new \Exception("Erreur lors de la requête Overpass : " . $e->getMessage());
}
}
public function get_osm_object_data($osm_object_id = 12855459190)
{
$object_id = "https://www.openstreetmap.org/api/0.6/node/".$osm_object_id;
try {
$response = $this->client->request('GET', $object_id);
$xml = simplexml_load_string($response->getContent());
$json = json_encode($xml);
$osm_object_data = json_decode($json, true);
} catch (\Exception $e) {
throw new \Exception("Impossible de récupérer les données OSM : " . $e->getMessage());
}
// convertir les tags en clés et valeurs
$osm_object_data['tags_converted'] = [];
foreach ($osm_object_data['node']['tag'] as $attribute) {
$osm_object_data['node']['tags_converted'][$attribute['@attributes']['k']] = $attribute['@attributes']['v'];
}
return $osm_object_data['node'];
}
public function semer(): string
{
return "La motocultrice sème les graines";
}
public function récolter(): string
{
return "La motocultrice récolte les cultures";
}
}

View file

@ -38,6 +38,18 @@
"migrations/.gitignore"
]
},
"php-http/discovery": {
"version": "1.20",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "1.18",
"ref": "f45b5dd173a27873ab19f5e3180b2f661c21de02"
},
"files": [
"config/packages/http_discovery.yaml"
]
},
"phpunit/phpunit": {
"version": "9.6",
"recipe": {

View file

@ -0,0 +1,20 @@
{% extends 'base.html.twig' %}
{% block title %}Hello AdminController!{% endblock %}
{% block body %}
<style>
.example-wrapper { margin: 1em auto; max-width: 800px; width: 95%; font: 18px/1.5 sans-serif; }
.example-wrapper code { background: #F5F5F5; padding: 2px 6px; }
</style>
<div class="example-wrapper">
<h1>Hello {{ controller_name }}! ✅</h1>
This friendly message is coming from:
<ul>
<li>Your controller at <code>/home/poule/encrypted/stockage-syncable/www/development/html/osm-commerce-sf/src/Controller/AdminController.php</code></li>
<li>Your template at <code>/home/poule/encrypted/stockage-syncable/www/development/html/osm-commerce-sf/templates/admin/index.html.twig</code></li>
</ul>
</div>
{% endblock %}

View file

@ -13,9 +13,6 @@
{{ encore_entry_link_tags('app') }}
{% endblock %}
{% block javascripts %}
{{ encore_entry_script_tags('app') }}
{% endblock %}
</head>
<body>
<header class="main-header">
@ -44,4 +41,8 @@
</div>
</footer>
</body>
{% block javascripts %}
{{ encore_entry_script_tags('app') }}
{% endblock %}
</html>

View file

@ -1,6 +1,6 @@
{% extends 'base.html.twig' %}
{% block title %}Hello PublicController!{% endblock %}
{% block title %}{{ 'display.title'|trans }}{% endblock %}
{% block stylesheets %}
{{ parent() }}
@ -24,13 +24,13 @@
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link active" href="{{ path('app_public_index') }}">Accueil</a>
<a class="nav-link active" href="{{ path('app_public_index') }}">{{ 'display.home'|trans }}</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{{ path('app_public_index') }}">Statistiques</a>
<a class="nav-link" href="{{ path('app_public_dashboard') }}">{{ 'display.stats'|trans }}</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{{ path('app_public_index') }}">Contacter un humain</a>
<a class="nav-link" href="https://openstreetmap.fr/contact/">{{ 'display.contact_humans'|trans }}</a>
</li>
</ul>
</div>
@ -43,12 +43,10 @@
<div class="col-12">
<div class="card shadow-sm">
<div class="card-body">
<h1 class="card-title mb-4">Bienvenue dans les commerces!</h1>
<div id="map" style="height: 400px; width: 100%;" class="rounded"></div>
<h1 class="card-title mb-4">{{ 'display.welcome'|trans }}</h1>
<div id="map" style="height: 400px; width: 100%;" class="rounded"></div>
{% if commerce is not empty %}
{# {{dump(commerce)}} #}
<div class="row mb-4">
<div class="col-12">
@ -57,56 +55,55 @@
<form action="{{ path('app_public_submit', {'osm_object_id': commerce['@attributes'].id, 'version': commerce['@attributes'].version, 'changesetID': commerce['@attributes'].changeset }) }}" method="post" class="needs-validation">
<div class="mb-3">
<label for="commerce_id" class="form-label">Modifier votre commerce:
<label for="commerce_id" class="form-label">{{ 'display.modify_commerce'|trans }}:
<strong>{{ commerce.tags_converted.name }}</strong>
</label>
<br/>
<a class="btn btn-info" href="{{ path('app_public_index') }}">{{ 'display.contact_humans' | trans}}</a>
<a class="btn btn-info" href="{{ path('app_public_index') }}">{{ 'display.contact_humans'|trans }}</a>
</div>
<h2>Tags</h2>
<h2>{{ 'display.tags'|trans }}</h2>
<fieldset>
{% for attributes in commerce.tag %}
{% for kv in attributes %}
{% if kv.k is 'opening_hours' %}
{{ 'display.keys.' ~ kv.k |trans}}
{% if kv.k == 'opening_hours' %}
{{ 'display.keys.opening_hours'|trans }}
{% else %}
<div class="row mb-3">
<div class="col-md-5">
<input type="text" class="form-control hidden" name="commerce_tag_key__{{ kv.k }}" value="{{ kv.k }}" readonly>
<span class="label-translated">{{ 'display.keys.' ~ kv.k |trans}}</span>
<div class="row mb-3">
<div class="col-md-5">
<input type="text" class="form-control hidden" name="commerce_tag_key__{{ kv.k }}" value="{{ kv.k }}" readonly>
<span class="label-translated">{{ ('display.keys.' ~ kv.k)|trans }}</span>
</div>
<div class="col-md-5">
<input type="text" class="form-control" name="commerce_tag_value__{{ kv.k }}" value="{{ kv.v }}">
</div>
</div>
<div class="col-md-5">
<input type="text" class="form-control" name="commerce_tag_value__{{ kv.k }}" value="{{ kv.v }}">
</div>
</div>
{% endif %}
{% endfor %}
{% endfor %}
</fieldset>
<button type="submit" class="btn btn-primary">Envoyer</button>
<button type="submit" class="btn btn-primary">{{ 'display.submit'|trans }}</button>
</form>
{% endif %}
</div>
</div>
</div>
<span class="last-modification">Dernière modification: {{ commerce['@attributes'].timestamp }}</span> par <a href="https://www.openstreetmap.org/user/{{ commerce['@attributes'].user }}" target="_blank">{{ commerce['@attributes'].user }}</a>
<div class="lien-OpenStreetMap">
<a href="https://www.openstreetmap.org/node/{{ commerce['@attributes'].id }}" target="_blank">Voir sur OpenStreetMap</a>
</div>
<span class="p-3">
<span class="last-modification">{{ 'display.last_modification'|trans }}: {{ commerce['@attributes'].timestamp }}</span>,
{{ 'display.days_ago'|trans({'%days%': date(commerce['@attributes'].timestamp).diff(date()).days}) }}
{{ 'display.by'|trans }}
<a href="https://www.openstreetmap.org/user/{{ commerce['@attributes'].user }}" target="_blank">{{ commerce['@attributes'].user }}</a>
<div class="lien-OpenStreetMap">
<a href="https://www.openstreetmap.org/node/{{ commerce['@attributes'].id }}" target="_blank">{{ 'display.view_on_osm'|trans }}</a>
</div>
</span>
<div class="disclaimer p-3">
<p>
<strong>Attention:</strong>
Ce site est un travail en cours, ceci est une démonstration sur un objet fictif qui utilise les données de l'API OpenStreetMap.
<strong>{{ 'display.disclaimer.title'|trans }}:</strong>
{{ 'display.disclaimer.text'|trans }}
</p>
</div>
</div>
@ -116,13 +113,10 @@
<nav class="bg-light p-3 rounded shadow-sm">
<ul class="nav justify-content-center">
<li class="nav-item">
<a class="nav-link" href="{{ path('app_public_index') }}">Accueil</a>
<a class="nav-link" href="{{ path('app_public_index') }}">{{ 'display.home'|trans }}</a>
</li>
{# <li class="nav-item">
<a class="nav-link" href="{{ path('app_public_index') }}">Statistiques</a>
</li> #}
<li class="nav-item">
<a class="nav-link" href="https://openstreetmap.fr/contact/">Contacter un humain</a>
<a class="nav-link" href="https://openstreetmap.fr/contact/">{{ 'display.contact_humans'|trans }}</a>
</li>
</ul>
</nav>

View file

@ -1,18 +0,0 @@
display:
contact_humans: "Contacter des humains d'OSM France pour m'aider"
modify: "Modifier"
keys:
- "tags" : "étiquettes"
- "name" : "Nom"
- "address" : "Adresse"
- "phone" : "Téléphone"
- "email" : "Email"
- "contact:phone" : "Téléphone du contact"
- "address:housenumber" : "Numéro de rue"
- "address:street" : "Rue"
- "address:city" : "Ville"
- "address:postcode" : "Code postal"
- "website" : "Site web"
- "contact:website" : "Contact du Site web"
- "opening_hours" : "Horaires d'ouverture"
- "shop" : "Type de commerce"

View file

@ -0,0 +1,33 @@
display:
title: "OSM My Shop"
home: "Home"
stats: "Statistics"
contact_humans: "Contact OSM France humans for help"
modify: "Modify"
welcome: "Welcome to the shops!"
modify_commerce: "Modify your shop"
tags: "Tags"
submit: "Submit"
last_modification: "Last modification"
days_ago: "%days% days ago"
by: "by"
view_on_osm: "View on OpenStreetMap"
keys:
tags: "tags"
name: "Name"
address: "Address"
phone: "Phone"
contact:email: "Email"
contact:phone: "Contact phone"
address:housenumber: "Street number"
address:street: "Street"
address:city: "City"
address:postcode: "Postal code"
website: "Website"
contact:website: "Contact website"
opening_hours: "Opening hours"
shop: "Shop type"
tourism: "Tourism"
disclaimer:
title: "Warning"
text: "This site is a work in progress, this is a demonstration on a fictional object using OpenStreetMap API data."

View file

@ -0,0 +1,33 @@
display:
title: "OSM Mon Commerce"
home: "Accueil"
stats: "Statistiques"
contact_humans: "Contacter des humains d'OSM France pour m'aider"
modify: "Modifier"
welcome: "Bienvenue dans les commerces!"
modify_commerce: "Modifier votre commerce"
tags: "Tags"
submit: "Envoyer"
last_modification: "Dernière modification"
days_ago: "il y a %days% jours"
by: "par"
view_on_osm: "Voir sur OpenStreetMap"
keys:
tags: "étiquettes"
name: "Nom"
address: "Adresse"
phone: "Téléphone"
contact:email: "Email"
contact:phone: "Téléphone du contact"
address:housenumber: "Numéro de rue"
address:street: "Rue"
address:city: "Ville"
address:postcode: "Code postal"
website: "Site web"
contact:website: "Contact du Site web"
opening_hours: "Horaires d'ouverture"
shop: "Type de commerce"
tourism: "Tourisme"
disclaimer:
title: "Attention"
text: "Ce site est un travail en cours, ceci est une démonstration sur un objet fictif qui utilise les données de l'API OpenStreetMap."