@ -0,0 +1,54 @@ | |||||
<?php | |||||
declare(strict_types=1); | |||||
namespace DoctrineMigrations; | |||||
use Doctrine\DBAL\Schema\Schema; | |||||
use Doctrine\Migrations\AbstractMigration; | |||||
/** | |||||
* Auto-generated Migration: Please modify to your needs! | |||||
*/ | |||||
final class Version20240802085751 extends AbstractMigration | |||||
{ | |||||
public function getDescription(): string | |||||
{ | |||||
return ''; | |||||
} | |||||
public function up(Schema $schema): void | |||||
{ | |||||
// this up() migration is auto-generated, please modify it to your needs | |||||
$this->addSql('CREATE TEMPORARY TABLE __temp__task AS SELECT id, project_id, created_by_id, locked_by_id, name, slug, urgent, important, status, geojson, osm, description, created_at, locked_at FROM task'); | |||||
$this->addSql('DROP TABLE task'); | |||||
$this->addSql('CREATE TABLE task (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, project_id INTEGER NOT NULL, created_by_id INTEGER NOT NULL, locked_by_id INTEGER DEFAULT NULL, done_by_id INTEGER DEFAULT NULL, name VARCHAR(255) NOT NULL, slug VARCHAR(255) NOT NULL, urgent INTEGER DEFAULT NULL, important INTEGER DEFAULT NULL, status VARCHAR(255) NOT NULL, geojson CLOB NOT NULL, osm CLOB DEFAULT NULL, description CLOB DEFAULT NULL, created_at DATETIME NOT NULL --(DC2Type:datetime_immutable) | |||||
, locked_at DATETIME DEFAULT NULL --(DC2Type:datetime_immutable) | |||||
, doing_start_at DATETIME DEFAULT NULL --(DC2Type:datetime_immutable) | |||||
, doing_end_at DATETIME DEFAULT NULL --(DC2Type:datetime_immutable) | |||||
, CONSTRAINT FK_527EDB25166D1F9C FOREIGN KEY (project_id) REFERENCES project (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_527EDB25B03A8386 FOREIGN KEY (created_by_id) REFERENCES user (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_527EDB257A88E00 FOREIGN KEY (locked_by_id) REFERENCES user (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_527EDB2535AE3EF9 FOREIGN KEY (done_by_id) REFERENCES user (id) NOT DEFERRABLE INITIALLY IMMEDIATE)'); | |||||
$this->addSql('INSERT INTO task (id, project_id, created_by_id, locked_by_id, name, slug, urgent, important, status, geojson, osm, description, created_at, locked_at) SELECT id, project_id, created_by_id, locked_by_id, name, slug, urgent, important, status, geojson, osm, description, created_at, locked_at FROM __temp__task'); | |||||
$this->addSql('DROP TABLE __temp__task'); | |||||
$this->addSql('CREATE INDEX IDX_527EDB257A88E00 ON task (locked_by_id)'); | |||||
$this->addSql('CREATE INDEX IDX_527EDB25B03A8386 ON task (created_by_id)'); | |||||
$this->addSql('CREATE INDEX IDX_527EDB25166D1F9C ON task (project_id)'); | |||||
$this->addSql('CREATE UNIQUE INDEX UNIQ_527EDB25989D9B62 ON task (slug)'); | |||||
$this->addSql('CREATE INDEX IDX_527EDB2535AE3EF9 ON task (done_by_id)'); | |||||
} | |||||
public function down(Schema $schema): void | |||||
{ | |||||
// this down() migration is auto-generated, please modify it to your needs | |||||
$this->addSql('CREATE TEMPORARY TABLE __temp__task AS SELECT id, project_id, created_by_id, locked_by_id, name, slug, urgent, important, status, geojson, osm, description, created_at, locked_at FROM task'); | |||||
$this->addSql('DROP TABLE task'); | |||||
$this->addSql('CREATE TABLE task (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, project_id INTEGER NOT NULL, created_by_id INTEGER NOT NULL, locked_by_id INTEGER DEFAULT NULL, name VARCHAR(255) NOT NULL, slug VARCHAR(255) NOT NULL, urgent INTEGER DEFAULT NULL, important INTEGER DEFAULT NULL, status VARCHAR(255) NOT NULL, geojson CLOB NOT NULL, osm CLOB DEFAULT NULL, description CLOB DEFAULT NULL, created_at DATETIME NOT NULL --(DC2Type:datetime_immutable) | |||||
, locked_at DATETIME DEFAULT NULL --(DC2Type:datetime_immutable) | |||||
, CONSTRAINT FK_527EDB25166D1F9C FOREIGN KEY (project_id) REFERENCES project (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_527EDB25B03A8386 FOREIGN KEY (created_by_id) REFERENCES user (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_527EDB257A88E00 FOREIGN KEY (locked_by_id) REFERENCES user (id) NOT DEFERRABLE INITIALLY IMMEDIATE)'); | |||||
$this->addSql('INSERT INTO task (id, project_id, created_by_id, locked_by_id, name, slug, urgent, important, status, geojson, osm, description, created_at, locked_at) SELECT id, project_id, created_by_id, locked_by_id, name, slug, urgent, important, status, geojson, osm, description, created_at, locked_at FROM __temp__task'); | |||||
$this->addSql('DROP TABLE __temp__task'); | |||||
$this->addSql('CREATE UNIQUE INDEX UNIQ_527EDB25989D9B62 ON task (slug)'); | |||||
$this->addSql('CREATE INDEX IDX_527EDB25166D1F9C ON task (project_id)'); | |||||
$this->addSql('CREATE INDEX IDX_527EDB25B03A8386 ON task (created_by_id)'); | |||||
$this->addSql('CREATE INDEX IDX_527EDB257A88E00 ON task (locked_by_id)'); | |||||
} | |||||
} |
@ -0,0 +1,57 @@ | |||||
<?php | |||||
declare(strict_types=1); | |||||
namespace DoctrineMigrations; | |||||
use Doctrine\DBAL\Schema\Schema; | |||||
use Doctrine\Migrations\AbstractMigration; | |||||
/** | |||||
* Auto-generated Migration: Please modify to your needs! | |||||
*/ | |||||
final class Version20240802090033 extends AbstractMigration | |||||
{ | |||||
public function getDescription(): string | |||||
{ | |||||
return ''; | |||||
} | |||||
public function up(Schema $schema): void | |||||
{ | |||||
// this up() migration is auto-generated, please modify it to your needs | |||||
$this->addSql('CREATE TEMPORARY TABLE __temp__task AS SELECT id, project_id, created_by_id, locked_by_id, done_by_id, name, slug, urgent, important, status, geojson, osm, description, created_at, locked_at FROM task'); | |||||
$this->addSql('DROP TABLE task'); | |||||
$this->addSql('CREATE TABLE task (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, project_id INTEGER NOT NULL, created_by_id INTEGER NOT NULL, locked_by_id INTEGER DEFAULT NULL, done_by_id INTEGER DEFAULT NULL, name VARCHAR(255) NOT NULL, slug VARCHAR(255) NOT NULL, urgent INTEGER DEFAULT NULL, important INTEGER DEFAULT NULL, status VARCHAR(255) NOT NULL, geojson CLOB NOT NULL, osm CLOB DEFAULT NULL, description CLOB DEFAULT NULL, created_at DATETIME NOT NULL --(DC2Type:datetime_immutable) | |||||
, locked_at DATETIME DEFAULT NULL --(DC2Type:datetime_immutable) | |||||
, start_at DATETIME DEFAULT NULL --(DC2Type:datetime_immutable) | |||||
, finish_at DATETIME DEFAULT NULL --(DC2Type:datetime_immutable) | |||||
, CONSTRAINT FK_527EDB25166D1F9C FOREIGN KEY (project_id) REFERENCES project (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_527EDB25B03A8386 FOREIGN KEY (created_by_id) REFERENCES user (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_527EDB257A88E00 FOREIGN KEY (locked_by_id) REFERENCES user (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_527EDB2535AE3EF9 FOREIGN KEY (done_by_id) REFERENCES user (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE)'); | |||||
$this->addSql('INSERT INTO task (id, project_id, created_by_id, locked_by_id, done_by_id, name, slug, urgent, important, status, geojson, osm, description, created_at, locked_at) SELECT id, project_id, created_by_id, locked_by_id, done_by_id, name, slug, urgent, important, status, geojson, osm, description, created_at, locked_at FROM __temp__task'); | |||||
$this->addSql('DROP TABLE __temp__task'); | |||||
$this->addSql('CREATE INDEX IDX_527EDB2535AE3EF9 ON task (done_by_id)'); | |||||
$this->addSql('CREATE UNIQUE INDEX UNIQ_527EDB25989D9B62 ON task (slug)'); | |||||
$this->addSql('CREATE INDEX IDX_527EDB25166D1F9C ON task (project_id)'); | |||||
$this->addSql('CREATE INDEX IDX_527EDB25B03A8386 ON task (created_by_id)'); | |||||
$this->addSql('CREATE INDEX IDX_527EDB257A88E00 ON task (locked_by_id)'); | |||||
} | |||||
public function down(Schema $schema): void | |||||
{ | |||||
// this down() migration is auto-generated, please modify it to your needs | |||||
$this->addSql('CREATE TEMPORARY TABLE __temp__task AS SELECT id, project_id, created_by_id, locked_by_id, done_by_id, name, slug, urgent, important, status, geojson, osm, description, created_at, locked_at FROM task'); | |||||
$this->addSql('DROP TABLE task'); | |||||
$this->addSql('CREATE TABLE task (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, project_id INTEGER NOT NULL, created_by_id INTEGER NOT NULL, locked_by_id INTEGER DEFAULT NULL, done_by_id INTEGER DEFAULT NULL, name VARCHAR(255) NOT NULL, slug VARCHAR(255) NOT NULL, urgent INTEGER DEFAULT NULL, important INTEGER DEFAULT NULL, status VARCHAR(255) NOT NULL, geojson CLOB NOT NULL, osm CLOB DEFAULT NULL, description CLOB DEFAULT NULL, created_at DATETIME NOT NULL --(DC2Type:datetime_immutable) | |||||
, locked_at DATETIME DEFAULT NULL --(DC2Type:datetime_immutable) | |||||
, doing_start_at DATETIME DEFAULT NULL --(DC2Type:datetime_immutable) | |||||
, doing_end_at DATETIME DEFAULT NULL --(DC2Type:datetime_immutable) | |||||
, CONSTRAINT FK_527EDB25166D1F9C FOREIGN KEY (project_id) REFERENCES project (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_527EDB25B03A8386 FOREIGN KEY (created_by_id) REFERENCES user (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_527EDB257A88E00 FOREIGN KEY (locked_by_id) REFERENCES user (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_527EDB2535AE3EF9 FOREIGN KEY (done_by_id) REFERENCES user (id) NOT DEFERRABLE INITIALLY IMMEDIATE)'); | |||||
$this->addSql('INSERT INTO task (id, project_id, created_by_id, locked_by_id, done_by_id, name, slug, urgent, important, status, geojson, osm, description, created_at, locked_at) SELECT id, project_id, created_by_id, locked_by_id, done_by_id, name, slug, urgent, important, status, geojson, osm, description, created_at, locked_at FROM __temp__task'); | |||||
$this->addSql('DROP TABLE __temp__task'); | |||||
$this->addSql('CREATE UNIQUE INDEX UNIQ_527EDB25989D9B62 ON task (slug)'); | |||||
$this->addSql('CREATE INDEX IDX_527EDB25166D1F9C ON task (project_id)'); | |||||
$this->addSql('CREATE INDEX IDX_527EDB25B03A8386 ON task (created_by_id)'); | |||||
$this->addSql('CREATE INDEX IDX_527EDB257A88E00 ON task (locked_by_id)'); | |||||
$this->addSql('CREATE INDEX IDX_527EDB2535AE3EF9 ON task (done_by_id)'); | |||||
} | |||||
} |
@ -0,0 +1,44 @@ | |||||
<?php | |||||
declare(strict_types=1); | |||||
namespace DoctrineMigrations; | |||||
use Doctrine\DBAL\Schema\Schema; | |||||
use Doctrine\Migrations\AbstractMigration; | |||||
/** | |||||
* Auto-generated Migration: Please modify to your needs! | |||||
*/ | |||||
final class Version20240802120611 extends AbstractMigration | |||||
{ | |||||
public function getDescription(): string | |||||
{ | |||||
return ''; | |||||
} | |||||
public function up(Schema $schema): void | |||||
{ | |||||
// this up() migration is auto-generated, please modify it to your needs | |||||
$this->addSql('ALTER TABLE task ADD COLUMN changesets_result CLOB DEFAULT NULL'); | |||||
} | |||||
public function down(Schema $schema): void | |||||
{ | |||||
// this down() migration is auto-generated, please modify it to your needs | |||||
$this->addSql('CREATE TEMPORARY TABLE __temp__task AS SELECT id, project_id, created_by_id, locked_by_id, done_by_id, name, slug, urgent, important, status, geojson, osm, description, created_at, locked_at, start_at, finish_at FROM task'); | |||||
$this->addSql('DROP TABLE task'); | |||||
$this->addSql('CREATE TABLE task (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, project_id INTEGER NOT NULL, created_by_id INTEGER NOT NULL, locked_by_id INTEGER DEFAULT NULL, done_by_id INTEGER DEFAULT NULL, name VARCHAR(255) NOT NULL, slug VARCHAR(255) NOT NULL, urgent INTEGER DEFAULT NULL, important INTEGER DEFAULT NULL, status VARCHAR(255) NOT NULL, geojson CLOB NOT NULL, osm CLOB DEFAULT NULL, description CLOB DEFAULT NULL, created_at DATETIME NOT NULL --(DC2Type:datetime_immutable) | |||||
, locked_at DATETIME DEFAULT NULL --(DC2Type:datetime_immutable) | |||||
, start_at DATETIME DEFAULT NULL --(DC2Type:datetime_immutable) | |||||
, finish_at DATETIME DEFAULT NULL --(DC2Type:datetime_immutable) | |||||
, CONSTRAINT FK_527EDB25166D1F9C FOREIGN KEY (project_id) REFERENCES project (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_527EDB25B03A8386 FOREIGN KEY (created_by_id) REFERENCES user (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_527EDB257A88E00 FOREIGN KEY (locked_by_id) REFERENCES user (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_527EDB2535AE3EF9 FOREIGN KEY (done_by_id) REFERENCES user (id) NOT DEFERRABLE INITIALLY IMMEDIATE)'); | |||||
$this->addSql('INSERT INTO task (id, project_id, created_by_id, locked_by_id, done_by_id, name, slug, urgent, important, status, geojson, osm, description, created_at, locked_at, start_at, finish_at) SELECT id, project_id, created_by_id, locked_by_id, done_by_id, name, slug, urgent, important, status, geojson, osm, description, created_at, locked_at, start_at, finish_at FROM __temp__task'); | |||||
$this->addSql('DROP TABLE __temp__task'); | |||||
$this->addSql('CREATE UNIQUE INDEX UNIQ_527EDB25989D9B62 ON task (slug)'); | |||||
$this->addSql('CREATE INDEX IDX_527EDB25166D1F9C ON task (project_id)'); | |||||
$this->addSql('CREATE INDEX IDX_527EDB25B03A8386 ON task (created_by_id)'); | |||||
$this->addSql('CREATE INDEX IDX_527EDB257A88E00 ON task (locked_by_id)'); | |||||
$this->addSql('CREATE INDEX IDX_527EDB2535AE3EF9 ON task (done_by_id)'); | |||||
} | |||||
} |
@ -0,0 +1,120 @@ | |||||
<?php | |||||
namespace App\EventSubscriber; | |||||
use App\Entity\Comment; | |||||
use App\Entity\Task; | |||||
use App\Service\OpenStreetMapClient; | |||||
use Doctrine\ORM\EntityManagerInterface; | |||||
use Symfony\Bundle\SecurityBundle\Security; | |||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface; | |||||
use Symfony\Component\Workflow\Event\EnteredEvent; | |||||
use Symfony\Component\Workflow\Event\Event; | |||||
use Symfony\Component\Workflow\Event\GuardEvent; | |||||
use Symfony\Component\Workflow\Event\TransitionEvent; | |||||
use Symfony\Component\Workflow\WorkflowInterface; | |||||
use Twig\Environment; | |||||
class TaskLifecycleSubscriber implements EventSubscriberInterface | |||||
{ | |||||
public function __construct( | |||||
protected EntityManagerInterface $entityManager, | |||||
protected Environment $twig, | |||||
protected OpenStreetMapClient $osmClient, | |||||
protected Security $security, | |||||
protected WorkflowInterface $taskLifecycleStateMachine, | |||||
) { | |||||
} | |||||
public function onTransition(Event $event): void | |||||
{ | |||||
$transition = $event->getTransition(); | |||||
$task = $event->getSubject(); | |||||
// Gère le verrouillage de la tâche | |||||
$shouldLock = $this->taskLifecycleStateMachine->getMetadataStore()->getTransitionMetadata($transition)['lock']; | |||||
$shouldUnlock = $this->taskLifecycleStateMachine->getMetadataStore()->getTransitionMetadata($transition)['unlock']; | |||||
if ($shouldLock) { | |||||
$task->lock($this->security->getUser()); | |||||
} elseif ($shouldUnlock) { | |||||
$task->unlock(); | |||||
} | |||||
// Commentaire automatique | |||||
$user = $this->security->getUser(); | |||||
$task = $event->getSubject(); | |||||
$comment = new Comment(); | |||||
$comment->setTask($task); | |||||
$comment->setCreatedBy($user); | |||||
$comment->setContent($this->twig->render(sprintf('comment/%s.md.twig', $transition->getName()), [ | |||||
'user' => $user, | |||||
'task' => $task, | |||||
])); | |||||
$this->entityManager->persist($comment); | |||||
$this->entityManager->flush(); | |||||
} | |||||
public function onGuard(Event $event): void | |||||
{ | |||||
$transition = $event->getTransition(); | |||||
$task = $event->getSubject(); | |||||
$shouldLock = $this->taskLifecycleStateMachine->getMetadataStore()->getTransitionMetadata($transition)['lock']; | |||||
$shouldUnlock = $this->taskLifecycleStateMachine->getMetadataStore()->getTransitionMetadata($transition)['unlock']; | |||||
$subject = $event->getSubject(); | |||||
if ($shouldLock and $task->isLocked()) { | |||||
$event->setBlocked(true, 'La tâche est déjà verrouillée.'); | |||||
} elseif ($shouldUnlock and !$task->isLocked()) { | |||||
$event->setBlocked(true, 'La tâche n’est pas déjà verrouillée.'); | |||||
} | |||||
$event->setBlocked(false); | |||||
} | |||||
public function onStart(Event $event): void | |||||
{ | |||||
$task = $event->getSubject(); | |||||
$task->setStartAt(new \DateTimeImmutable('now')); | |||||
} | |||||
public function onFinish(Event $event): void | |||||
{ | |||||
$task = $event->getSubject(); | |||||
$task->setFinishAt(new \DateTimeImmutable('now')); | |||||
} | |||||
public function onDone(Event $event): void | |||||
{ | |||||
$task = $event->getSubject(); | |||||
$user = $this->security->getUser(); | |||||
$task->setDoneBy($user); | |||||
$task->setChangesetsResult( | |||||
json_encode($this->osmClient()->getChangesets( | |||||
$user->getUsername(), | |||||
$task->getStartAt(), | |||||
$task->getFinishAt() | |||||
)) | |||||
); | |||||
} | |||||
public static function getSubscribedEvents(): array | |||||
{ | |||||
return [ | |||||
TransitionEvent::getName('task_lifecycle', null) => 'onTransition', | |||||
GuardEvent::getName('task_lifecycle', null) => 'onGuard', | |||||
TransitionEvent::getName('task_lifecycle', Task::TRANSITION_START) => 'onStart', | |||||
TransitionEvent::getName('task_lifecycle', Task::TRANSITION_FINISH) => 'onFinish', | |||||
EnteredEvent::getName('task_lifecycle', Task::STATUS_DONE) => 'onDone', | |||||
]; | |||||
} | |||||
} |
@ -0,0 +1,84 @@ | |||||
<?php | |||||
namespace App\Service; | |||||
use KnpU\OAuth2ClientBundle\Client\ClientRegistry; | |||||
use Symfony\Component\HttpFoundation\RequestStack; | |||||
use Symfony\Contracts\HttpClient\HttpClientInterface; | |||||
class OpenStreetMapClient { | |||||
public function __construct( | |||||
private ClientRegistry $clientRegistry, | |||||
private HttpClientInterface $client, | |||||
private RequestStack $requestStack, | |||||
) { | |||||
} | |||||
protected function query(string $method, string $path, array $params = []) | |||||
{ | |||||
$session = $this->requestStack->getSession(); | |||||
$accessToken = $session->get('access_token'); | |||||
/* | |||||
if ($accessToken->hasExpired()) { | |||||
$accessToken = $this->clientRegistry->getClient('openstreetmap')->refreshAccessToken($accessToken->getRefreshToken()); | |||||
$session->set('access_token', $accessToken); | |||||
} | |||||
*/ | |||||
$token = $accessToken->getToken(); | |||||
$response = $this->client->request($method, 'https://api.openstreetmap.org/api/0.6/' . $path, [ | |||||
'auth_bearer' => $token, | |||||
'query' => $params, | |||||
]); | |||||
$isStatusCodeOk = ($response->getStatusCode() === 200); | |||||
if (!$isStatusCodeOk) { | |||||
throw new \RuntimeException(); | |||||
} | |||||
return $response->getContent(); | |||||
} | |||||
/* Cf <https://wiki.openstreetmap.org/wiki/API_v0.6#Query:_GET_/api/0.6/changesets> */ | |||||
public function getChangesets(?string $username = null, ?\DateTimeInterface $since = null, ?\DateTimeInterface $then = null) | |||||
{ | |||||
$changesets = []; | |||||
$params = []; | |||||
if (!is_null($username)) { | |||||
$params['display_name'] = $username; | |||||
} | |||||
if (!is_null($since) and !is_null($then)) { | |||||
$params['time'] = implode(',', [ | |||||
$since->format(\DateTimeInterface::ISO8601), | |||||
$then->format(\DateTimeInterface::ISO8601), | |||||
]); | |||||
} elseif (!is_null($since) and is_null($then)) { | |||||
$params['time'] = $since->format(\DateTimeInterface::ISO8601); | |||||
} | |||||
$response = $this->query('GET', 'changesets', $params); | |||||
$xml = new \DOMDocument(); | |||||
$xml->loadXML($response); | |||||
$xpath = new \DOMXPath($xml); | |||||
$changesetNodes = $xpath->query('/osm/changeset'); | |||||
foreach ($changesetNodes as $changesetNode) { | |||||
$changeset = []; | |||||
foreach ($changesetNode->attributes as $attribute) { | |||||
$changeset[$attribute->name] = $attribute->value; | |||||
} | |||||
$tagNodes = $xpath->query('./tag', $changesetNode); | |||||
foreach ($tagNodes as $tagNode) { | |||||
$changeset[$tagNode->getAttribute('k')] = $tagNode->getAttribute('v'); | |||||
} | |||||
$changesets[] = $changeset; | |||||
} | |||||
return $changesets; | |||||
} | |||||
} |
@ -0,0 +1,29 @@ | |||||
<?php | |||||
/* | |||||
min_lat="44.1762654" min_lon="4.0874079" max_lat="44.2089911" max_lon="4.1176352" | |||||
curl 'https://osmose.openstreetmap.fr/api/0.3/issues?bbox=4.0874079,44.1762654,4.1176352,44.2089911&username=caboulot' | |||||
curl 'https://osmose.openstreetmap.fr/api/0.3/issues?bbox=4.0874079,44.1762654,4.1176352,44.2089911' | |||||
{"issues":[{"lat":44.1794503,"lon":4.088304,"id":"b1ff426d-dcad-71ed-1d2a-6c2046bf1ba8","item":"8500"},{"lat":44.1780477,"lon":4.0904077,"id":"fbd4dc15-473c-b180-df76-270f27d20f49","item":"8100"},{"lat":44.1804446,"lon":4.0925989,"id":"b36d1a0a-2d9f-5ece-9df6-f029c4988f5c","item":"8100"},{"lat":44.176561,"lon":4.1107394,"id":"060128fb-52ee-b07b-701b-0e08c2845e2f","item":"8100"},{"lat":44.1780305,"lon":4.111765,"id":"962b9b5c-cd23-6599-97af-e826714bd1d4","item":"8100"},{"lat":44.1838506,"lon":4.1046709,"id":"9a958f77-82b0-97c9-c201-ca2f59be1c92","item":"8100"},{"lat":44.177464,"lon":4.097858,"id":"1e1c187c-c4dc-aefb-b3b5-7efde7094793","item":"1230"},{"lat":44.1851377,"lon":4.1068794,"id":"31d93adf-ea1c-8fd2-6d81-af675592c9ae","item":"8280"},{"lat":44.1852151,"lon":4.1098047,"id":"020388a0-5b51-a223-8ce2-f5bdbdafc462","item":"8280"},{"lat":44.1778859,"lon":4.1118038,"id":"3ad94aec-a112-caaf-0e05-3000b8ea713b","item":"8280"},{"lat":44.1771659,"lon":4.0946588,"id":"77adb92d-7a47-af45-a9f3-1e8bb9f77f0f","item":"8280"},{"lat":44.1792438,"lon":4.0910476,"id":"616a6997-6679-85c5-0aea-94d30842e730","item":"8260"},{"lat":44.177985,"lon":4.091316,"id":"3511f1a6-5b22-f33a-08a0-6e282c0f186d","item":"8310"},{"lat":44.179733,"lon":4.09073,"id":"23b66128-22ee-b3b6-07cb-9716778675ff","item":"7170"},{"lat":44.1983061,"lon":4.1083305,"id":"eedd870f-44b0-cc77-e2b1-b892b32a5ada","item":"8280"},{"lat":44.177167,"lon":4.105044,"id":"6adee921-9dc1-9512-f80c-c250b45f0402","item":"8310"},{"lat":44.179557,"lon":4.105813,"id":"e9b3aedf-b251-5e4a-aff2-d47303a5fe0d","item":"8310"},{"lat":44.1900522,"lon":4.0960352,"id":"e9d11fcd-83bd-307b-771d-9b134a7bfb4b","item":"2130"},{"lat":44.1882819,"lon":4.0974304,"id":"44317976-917b-e246-97ca-d0957c56396e","item":"3091"},{"lat":44.1814147,"lon":4.111102,"id":"1fd7c71a-5b33-18bc-9491-41a725c20eac","item":"5080"},{"lat":44.18067,"lon":4.11218,"id":"846eb7d2-3a6b-4a28-887f-17775482148d","item":"8170"},{"lat":44.183475,"lon":4.111835,"id":"62977de3-898f-5408-a854-d8b11374705b","item":"8310"},{"lat":44.183475,"lon":4.111835,"id":"14256577-f477-bdd7-0d59-aaf8ebf591a4","item":"8310"},{"lat":44.1808883,"lon":4.1130807,"id":"c5076142-ef71-d3b8-404e-87829c8a2328","item":"9001"},{"lat":44.1805634,"lon":4.1152882,"id":"9f6a686a-a5dc-f729-82a0-7faf48e8c428","item":"9001"},{"lat":44.1861172,"lon":4.103424,"id":"92ea4bef-1a7e-74bc-2a43-7927433095cd","item":"8530"},{"lat":44.1832749,"lon":4.1110508,"id":"75435dce-7b79-cfcb-7ecc-4df42a3cb7ab","item":"8100"},{"lat":44.176445,"lon":4.1148587,"id":"e3b91e9e-052a-c0f0-5e46-14df8c5ce01b","item":"8280"},{"lat":44.1765674,"lon":4.1074229,"id":"1a033442-2212-af3f-21b9-d1283bddc949","item":"8280"},{"lat":44.1830498,"lon":4.1095534,"id":"59842e30-7fcc-a7b0-76c7-7584848672bc","item":"8280"},{"lat":44.1870279,"lon":4.1117828,"id":"2ca1e7ad-2c95-7146-aef0-6e8df970122d","item":"8500"},{"lat":44.1772469,"lon":4.0947452,"id":"501299b6-da5b-c95e-347e-fad8cf62ab9c","item":"1210"},{"lat":44.177329,"lon":4.096523,"id":"c874c7e8-1118-e959-f050-96302b319b32","item":"8310"},{"lat":44.1866871,"lon":4.0977601,"id":"e8d04270-e146-a4d5-760a-a3a2316ee898","item":"9006"},{"lat":44.1866871,"lon":4.0977601,"id":"f154b78d-5360-f971-b736-6489c7df670e","item":"3091"},{"lat":44.1817631,"lon":4.0895483,"id":"907291b9-ac78-faf8-1ad0-f36f3d859afb","item":"8010"},{"lat":44.1791288,"lon":4.0954703,"id":"1ccdc69c-29be-48a3-232c-91c2dadaa799","item":"1230"},{"lat":44.1810253,"lon":4.1044074,"id":"aa17ed0c-b354-4c81-728c-39926fbb759d","item":"8280"},{"lat":44.1832127,"lon":4.111835,"id":"2c8ae62c-0db2-474e-f05a-e2dc6ebcee73","item":"7170"},{"lat":44.1882819,"lon":4.0974304,"id":"e6dd4e37-f745-cad9-126c-5507a733d70c","item":"9006"},{"lat":44.1793645,"lon":4.0918519,"id":"c2ad06be-da22-44a9-d902-e10c96dc686f","item":"8280"},{"lat":44.1791669,"lon":4.0927244,"id":"bec7d376-3596-8926-3cac-be61cac97f0c","item":"8100"},{"lat":44.1775655,"lon":4.0904883,"id":"502cd4b5-3330-221e-f696-e14655727126","item":"8280"},{"lat":44.1800258,"lon":4.0992066,"id":"6e74f642-2c7a-c6ee-d101-4bd6847ece68","item":"8100"},{"lat":44.1823563,"lon":4.0940009,"id":"89f6c38f-e3be-247f-f818-287c89918362","item":"8280"},{"lat":44.2045949,"lon":4.0887296,"id":"b6d4a358-fee6-454f-a8b1-9fd8f37f6456","item":"8280"}]} | |||||
issues.rss | |||||
issues.geojson | |||||
curl 'https://osmose.openstreetmap.fr/api/0.3/user/caboulot' par user | |||||
*/ | |||||
namespace App\Service; | |||||
use Symfony\Contracts\HttpClient\HttpClientInterface; | |||||
class OsmoseClient { | |||||
public function __construct( | |||||
private HttpClientInterface $client, | |||||
) { | |||||
} | |||||
} |