diff --git a/composer.json b/composer.json index 562df1d34..23c2db1cb 100644 --- a/composer.json +++ b/composer.json @@ -15,6 +15,7 @@ "captioning/captioning": "^2.6", "ccmbenchmark/ting_bundle": "3.4.1", "cocur/slugify": "^2.3", + "cuyz/valinor": "^0.17.1", "doctrine/dbal": "^2.5", "ekino/newrelic-bundle": "^1.4", "erusev/parsedown": "^1.6", diff --git a/composer.lock b/composer.lock index b01ab3c91..1cddde81e 100644 --- a/composer.lock +++ b/composer.lock @@ -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": "6926657881db559a6711d0030446f20c", + "content-hash": "17064483ac9ca136d34329a42da629f9", "packages": [ { "name": "algolia/algoliasearch-client-php", @@ -492,6 +492,80 @@ }, "time": "2017-03-23T21:52:55+00:00" }, + { + "name": "cuyz/valinor", + "version": "0.17.1", + "source": { + "type": "git", + "url": "https://github.com/CuyZ/Valinor.git", + "reference": "8dbd01df82bf3eaf57246d1493d54b958b00f900" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/CuyZ/Valinor/zipball/8dbd01df82bf3eaf57246d1493d54b958b00f900", + "reference": "8dbd01df82bf3eaf57246d1493d54b958b00f900", + "shasum": "" + }, + "require": { + "composer-runtime-api": "^2.0", + "doctrine/annotations": "^1.11", + "php": "~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0", + "psr/simple-cache": "^1.0 || ^2.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3.4", + "infection/infection": "^0.26", + "marcocesarato/php-conventional-changelog": "^1.12", + "mikey179/vfsstream": "^1.6.10", + "phpstan/phpstan": "^1.3", + "phpstan/phpstan-phpunit": "^1.0", + "phpstan/phpstan-strict-rules": "^1.0", + "phpunit/phpunit": "^9.5", + "rector/rector": "^0.12.23", + "vimeo/psalm": "^4.18.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "CuyZ\\Valinor\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Romain Canon", + "email": "romain.hydrocanon@gmail.com", + "homepage": "https://github.com/romm" + } + ], + "description": "Library that helps to map any input into a strongly-typed value object structure.", + "homepage": "https://github.com/CuyZ/Valinor", + "keywords": [ + "array", + "conversion", + "hydrator", + "json", + "mapper", + "mapping", + "object", + "tree", + "yaml" + ], + "support": { + "issues": "https://github.com/CuyZ/Valinor/issues", + "source": "https://github.com/CuyZ/Valinor/tree/0.17.1" + }, + "funding": [ + { + "url": "https://github.com/romm", + "type": "github" + } + ], + "time": "2023-01-18T09:52:40+00:00" + }, { "name": "doctrine/annotations", "version": "1.14.4", @@ -7611,6 +7685,7 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { + "php": "7.4.* | 8.2.*", "ext-curl": "*", "ext-dom": "*", "ext-gd": "*", diff --git a/sources/AppBundle/Event/Model/Meetup.php b/sources/AppBundle/Event/Model/Meetup.php index 37f50a627..e7bdc44c9 100644 --- a/sources/AppBundle/Event/Model/Meetup.php +++ b/sources/AppBundle/Event/Model/Meetup.php @@ -70,7 +70,7 @@ public function getDate() } /** - * @param DateTime $date + * @param \DateTimeInterface $date * * @return Meetup */ diff --git a/sources/AppBundle/Indexation/Meetups/GraphQL/Edge.php b/sources/AppBundle/Indexation/Meetups/GraphQL/Edge.php new file mode 100644 index 000000000..f6a9f7b2e --- /dev/null +++ b/sources/AppBundle/Indexation/Meetups/GraphQL/Edge.php @@ -0,0 +1,19 @@ +node = $node; + } + + public function getNode(): Node + { + return $this->node; + } +} diff --git a/sources/AppBundle/Indexation/Meetups/GraphQL/Events.php b/sources/AppBundle/Indexation/Meetups/GraphQL/Events.php new file mode 100644 index 000000000..c6c9694dc --- /dev/null +++ b/sources/AppBundle/Indexation/Meetups/GraphQL/Events.php @@ -0,0 +1,26 @@ +edges = $edges; + } + + /** + * @return Edge[] + */ + public function getEdges(): array + { + return $this->edges; + } +} diff --git a/sources/AppBundle/Indexation/Meetups/GraphQL/Group.php b/sources/AppBundle/Indexation/Meetups/GraphQL/Group.php new file mode 100644 index 000000000..91b5b78d3 --- /dev/null +++ b/sources/AppBundle/Indexation/Meetups/GraphQL/Group.php @@ -0,0 +1,27 @@ +upcomingEvents = $upcomingEvents; + $this->pastEvents = $pastEvents; + } + + public function getUpcomingEvents(): Events + { + return $this->upcomingEvents; + } + + public function getPastEvents(): Events + { + return $this->pastEvents; + } +} diff --git a/sources/AppBundle/Indexation/Meetups/GraphQL/Node.php b/sources/AppBundle/Indexation/Meetups/GraphQL/Node.php new file mode 100644 index 000000000..77fe4450c --- /dev/null +++ b/sources/AppBundle/Indexation/Meetups/GraphQL/Node.php @@ -0,0 +1,48 @@ +id = $id; + $this->title = $title; + $this->eventUrl = $eventUrl; + $this->dateTime = $dateTime; + } + + public function getId(): string + { + return $this->id; + } + + public function getTitle(): string + { + return $this->title; + } + + public function getEventUrl(): string + { + return $this->eventUrl; + } + + public function getDateTime(): DateTimeImmutable + { + return $this->dateTime; + } +} diff --git a/sources/AppBundle/Indexation/Meetups/GraphQL/QueryGroupsResponse.php b/sources/AppBundle/Indexation/Meetups/GraphQL/QueryGroupsResponse.php new file mode 100644 index 000000000..796f542c0 --- /dev/null +++ b/sources/AppBundle/Indexation/Meetups/GraphQL/QueryGroupsResponse.php @@ -0,0 +1,26 @@ + */ + private array $data; + + /** + * @param array $data + */ + public function __construct(array $data) + { + $this->data = $data; + } + + /** + * @return array + */ + public function getData(): array + { + return $this->data; + } +} diff --git a/sources/AppBundle/Indexation/Meetups/MeetupClient.php b/sources/AppBundle/Indexation/Meetups/MeetupClient.php new file mode 100644 index 000000000..fcd4c3012 --- /dev/null +++ b/sources/AppBundle/Indexation/Meetups/MeetupClient.php @@ -0,0 +1,110 @@ +client = $client; + } + + /** + * @return Meetup[] + */ + public function getEvents(): array + { + $response = $this->client->request('POST', 'https://www.meetup.com/gql', [ + 'body' => $this->getEventsQuery(), + 'headers' => [ + 'Content-Type' => 'application/json', + ], + ]); + + try { + /** @var QueryGroupsResponse $groupResponse */ + $groupResponse = (new MapperBuilder()) + ->mapper() + ->map(QueryGroupsResponse::class, Source::json($response->getBody()->getContents())); + } catch (MappingError $error) { + throw new \Exception("todo", 0, $error); + } + + $meetups = []; + + foreach ($groupResponse->getData() as $nameAntenne => $group) { + foreach ($group->getUpcomingEvents()->getEdges() as $edge) { + $meetup = new Meetup(); + $meetup->setId((int)$edge->getNode()->getId()); + $meetup->setTitle($edge->getNode()->getTitle()); + $meetup->setDate($edge->getNode()->getDateTime()); + $meetup->setAntenneName($nameAntenne); + + $meetups[] = $meetup; + } + + foreach ($group->getPastEvents()->getEdges() as $edge) { + $meetup = new Meetup(); + $meetup->setId((int)$edge->getNode()->getId()); + $meetup->setTitle($edge->getNode()->getTitle()); + $meetup->setDate($edge->getNode()->getDateTime()); + $meetup->setAntenneName($nameAntenne); + + $meetups[] = $meetup; + } + } + + return $meetups; + } + + private function getEventsQuery(): string + { + $query = "query {\n"; + + foreach ((new OfficesCollection())->getAll() as $name => $office) { + $meetupId = $office['meetup_id']; + $query .= "$name: group(id: $meetupId) { ...GroupFragment }\n"; + } + + $query .= <<, + * departements: array, + * pays?: array, + * hide_on_offices_page?: bool, + * map_use_second_color?: bool, + * } + */ class OfficesCollection { - public function getAll() + /** + * @return OfficeType[] + */ + public function getAll(): array { return [ 'bordeaux' => [