diff --git a/README.md b/README.md
new file mode 100644
index 0000000..1d83373
--- /dev/null
+++ b/README.md
@@ -0,0 +1,198 @@
+This library allows you to easily communicate with BIS API.
+
+# Installation
+
+## Composer
+
+Add path to `repositories`:
+
+```
+{
+ "url": "https://github.com/hnuti-brontosaurus/php-bis-api-client.git",
+ "type": "vcs"
+}
+```
+
+and install package:
+```
+composer require hnuti-brontosaurus/php-bis-api-client
+```
+
+## Manually
+
+Download latest version from [github](https://github.com/hnuti-brontosaurus/php-bis-api-client/releases) to your computer.
+
+
+# Usage
+
+First you need to create client instance. Note that you need to know the API URL and obtain client ID and secret from BIS administrator
+to be able to authenticate against BIS.
+
+```php
+$client = (new BisClientFactory(
+ 'apiUrl',
+ 'clientId',
+ 'clientSecret',
+))->create();
+```
+
+Now you can perform any of available operations.
+
+## Events
+
+### Single event
+
+Retrieve all information about single event:
+
+```php
+$event = $client->getEvent($id);
+
+// examples of reading data
+$event->getName();
+$event->getOrganizer()->getResponsiblePerson();
+$event->getRegistrationType()->isOfTypeCustomWebpage();
+$event->getPlace()->getCoordinates();
+```
+
+### More events
+
+Retrieve all information about multiple events.
+
+Basic usage:
+
+```php
+$parameters = new \HnutiBrontosaurus\BisClient\Request\Event\EventParameters();
+$events = $client->getEvents($parameters); // $parameters are optional
+
+// example of reading data
+foreach ($events as $event) {
+ $event->getName();
+}
+```
+
+#### Filters
+
+You can filter in many ways:
+
+```php
+$parameters = new \HnutiBrontosaurus\BisClient\Request\Event\EventParameters();
+
+// only events of "voluntary" type
+$parameters->setType(\HnutiBrontosaurus\BisClient\Enums\EventType::VOLUNTARY());
+
+// only events of "PsB" program
+$parameters->setProgram(\HnutiBrontosaurus\BisClient\Enums\Program::PSB());
+
+// only events of "first time attendees" target group
+$parameters->setTargetGroup(\HnutiBrontosaurus\BisClient\Enums\TargetGroup::FIRST_TIME_ATTENDEES());
+
+// only events organized by organizational unit with ID 123
+$parameters->setOrganizedBy(123);
+
+// excludes running events
+$parameters->excludeRunning();
+
+$events = $client->getEvents($parameters);
+```
+
+For type, program and target group, you can set more values at once:
+
+```php
+$parameters = new \HnutiBrontosaurus\BisClient\Request\Event\EventParameters();
+
+$parameters->setTypes([
+ \HnutiBrontosaurus\BisClient\Enums\EventType::VOLUNTARY(),
+ \HnutiBrontosaurus\BisClient\Enums\EventType::SPORT(),
+]);
+
+$events = $client->getEvents($parameters);
+```
+
+Note that each method call rewrites the previous one:
+
+```php
+$parameters = new \HnutiBrontosaurus\BisClient\Request\Event\EventParameters();
+
+// sets "voluntary" type
+$parameters->setType(\HnutiBrontosaurus\BisClient\Enums\EventType::VOLUNTARY());
+// rewrites type with "sport"
+$parameters->setType(\HnutiBrontosaurus\BisClient\Enums\EventType::SPORT());
+
+$events = $client->getEvents($parameters);
+```
+
+#### Sorting
+
+You can even use some basic sorting options:
+
+```php
+$parameters = new \HnutiBrontosaurus\BisClient\Request\Event\EventParameters();
+
+// sort events by date from or date to
+$parameters->orderByDateFrom();
+$parameters->orderByDateTo(); // default
+
+$events = $client->getEvents($parameters);
+```
+
+### Adding attendee
+
+You can add attendee to an event:
+
+```php
+$client->addAttendee(new \HnutiBrontosaurus\BisClient\Request\Event\EventAttendee(
+ 123, // event ID
+ 'Jan', // first name
+ 'Novák', // last name
+ '12.3.2004', // birth date
+ '123 456 789', // phone number
+ 'jan@novak.cz', // e-mail address
+ 'poznámka', // note
+ ['odpověď na otázku č. 1', '', 'odpověď na otázku č. 3'], // answers to optional questions (optional)
+));
+```
+
+## Organizational units
+
+Retrieve all information about all organizational units:
+
+```php
+$organizationalUnits = $client->getOrganizationalUnits();
+
+// example of reading data
+foreach ($organizationalUnits as $organizationalUnit) {
+ $organizationalUnit->getName();
+ $organizationalUnit->getCity();
+ $organizationalUnit->getChairman();
+ $organizationalUnit->getCoordinates();
+}
+```
+
+# Development
+
+## Installation
+
+```
+composer install
+```
+
+## Structure
+
+- `docs` – instruction on how connection between brontoweb and BIS works (todo: move to brontoweb repo)
+- `src` – source code
+ - `Enums` – basic enum types
+ - `Request` – request-related value objects
+ - `Response` – request-related value objects and exceptions
+ - `BisClient` – client itself, serves for making requests to BIS API
+ - `BisClientFactory` – collects configuration data, ensures authentication against BIS and returns `BisClient`
+ - `HttpClient` – wrapper around Guzzle client which adds BIS API specific pieces into the request
+- `tests` – test code
+
+**Note that this library bundles Guzzle HTTP client as we can not rely on having composer in user's codebase.**
+
+## Tests
+
+This library has just `tests/index.php` which – if run on a webserver – will
+pass or fail visually – no error and results output or an exception.
+
+Note that you have to obtain client ID and secret as well to be able to run the test. Ask BIS administrator to get it, copy `tests/secret.template.php` to `tests/secret.php` and insert credentials there.
diff --git a/composer.json b/composer.json
index 0718a46..0fc5db9 100644
--- a/composer.json
+++ b/composer.json
@@ -11,9 +11,8 @@
"minimum-stability": "stable",
"require": {
"php": ">=8.0",
- "ext-dom": "*",
"grifart/enum": "^0.2.1",
- "guzzlehttp/guzzle": "^6.3"
+ "guzzlehttp/guzzle": "^7.3"
},
"require-dev": {
"phpstan/phpstan": "^0.12.88",
@@ -21,12 +20,10 @@
},
"autoload": {
"psr-4": {
- "HnutiBrontosaurus\\BisApiClient\\": "src/"
+ "HnutiBrontosaurus\\BisClient\\": "src/"
},
"classmap": [
- "src/exceptions.php",
- "src/Response/exceptions.php",
- "src/Response/OrganizationalUnit/exceptions.php"
+ "src/exceptions.php"
]
},
"config": {
diff --git a/src/Authenticator.php b/src/Authenticator.php
new file mode 100644
index 0000000..9a96927
--- /dev/null
+++ b/src/Authenticator.php
@@ -0,0 +1,65 @@
+token = null; // not yet authenticated
+ }
+
+
+ /**
+ * @throws UnableToAuthorize
+ * @throws ConnectionToBisFailed
+ */
+ public function authenticate(): AuthorizationToken
+ {
+ if ($this->token !== null) {
+ return $this->token;
+ }
+
+ try {
+ $response = $this->httpClient->send(new Request(
+ 'POST',
+ Endpoint::AUTHENTICATION(),
+ [
+ 'Accept' => 'application/json',
+ 'Content-Type' => 'application/json',
+ ],
+ \json_encode([
+ 'grant_type' => 'client_credentials',
+ 'client_id' => $this->clientId,
+ 'client_secret' => $this->clientSecret,
+ ]),
+ ));
+ } catch (ClientException $e) {
+ if ($e->getCode() === 401) {
+ throw UnableToAuthorize::withPrevious($e);
+ }
+
+ throw ConnectionToBisFailed::withPrevious($e);
+
+ } catch (GuzzleException $e) {
+ throw ConnectionToBisFailed::withPrevious($e);
+ }
+
+ $payload = \json_decode($response->getBody()->getContents());
+ $this->token = AuthorizationToken::from($payload->access_token);
+ return $this->token;
+ }
+
+}
diff --git a/src/AuthorizationToken.php b/src/AuthorizationToken.php
new file mode 100644
index 0000000..35b6c71
--- /dev/null
+++ b/src/AuthorizationToken.php
@@ -0,0 +1,28 @@
+value;
+ }
+
+ public function __toString(): string
+ {
+ return $this->toString();
+ }
+
+}
diff --git a/src/BisClient.php b/src/BisClient.php
new file mode 100644
index 0000000..74c1247
--- /dev/null
+++ b/src/BisClient.php
@@ -0,0 +1,90 @@
+httpClient->send('GET', Endpoint::EVENT($id));
+
+ \assert($data instanceof \stdClass);
+ return Event::fromResponseData($data);
+ }
+
+
+ /**
+ * @return Event[]
+ * @throws ConnectionToBisFailed
+ */
+ public function getEvents(?EventParameters $params = null): array
+ {
+ $data = $this->httpClient->send(
+ 'GET', Endpoint::EVENTS(),
+ $params !== null
+ ? $params
+ : new EventParameters(),
+ );
+
+ if ($data === null) {
+ return [];
+ }
+
+ \assert(\is_array($data));
+ return \array_map(Event::class . '::fromResponseData', $data);
+ }
+
+
+ /**
+ * @throws ConnectionToBisFailed
+ */
+ public function addAttendee(EventAttendee $eventAttendee): void
+ {
+ $this->httpClient->send('POST', Endpoint::ADD_ATTENDEE_TO_EVENT(), null, $eventAttendee);
+ }
+
+
+ // organizational units
+
+ /**
+ * @return OrganizationalUnit[]
+ * @throws ConnectionToBisFailed
+ */
+ public function getOrganizationalUnits(): array
+ {
+ $data = $this->httpClient->send('GET', Endpoint::ADMINISTRATIVE_UNITS());
+
+ if ($data === null) {
+ return [];
+ }
+
+ \assert(\is_array($data));
+ return \array_map(OrganizationalUnit::class . '::fromResponseData', $data);
+ }
+
+
+ // adoption
+
+ // not yet implemented
+// public function saveRequestForAdoption(Adoption $adoption): void
+// {}
+
+}
diff --git a/src/BisClientFactory.php b/src/BisClientFactory.php
new file mode 100644
index 0000000..551a140
--- /dev/null
+++ b/src/BisClientFactory.php
@@ -0,0 +1,47 @@
+httpClient = new Client(['base_uri' => \rtrim($apiUrl, '/') . '/']);
+ $this->bisAuthenticator = new Authenticator(
+ $this->clientId,
+ $this->clientSecret,
+ $this->httpClient,
+ );
+ }
+
+
+ /**
+ * @throws UnableToAuthorize
+ * @throws ConnectionToBisFailed
+ */
+ public function create(): BisClient
+ {
+ $token = $this->bisAuthenticator->authenticate();
+ return new BisClient(new HttpClient(
+ $token,
+ $this->httpClient,
+ ));
+ }
+
+}
diff --git a/src/Client.php b/src/Client.php
deleted file mode 100644
index 9c3c237..0000000
--- a/src/Client.php
+++ /dev/null
@@ -1,260 +0,0 @@
-url = \rtrim($url, '/');
- $this->username = $username;
- $this->password = $password;
- $this->httpClient = $httpClient;
- }
-
-
- // events
-
- /**
- * @throws NotFoundException
- * @throws TransferErrorException
- * @throws ResponseErrorException
- */
- public function getEvent(int $id, EventParameters $params = null): Event
- {
- $params = ($params !== null ? $params : new EventParameters());
- $params->setId($id);
- $response = $this->processRequest($params);
-
- $data = $response->getData();
-
- if (\count($data) === 0) {
- throw new NotFoundException('No result for event with id `' . $id . '`.');
- }
-
- return Event::fromResponseData(\reset($data));
- }
-
-
- /**
- * @return Event[]
- * @throws NotFoundException
- * @throws TransferErrorException
- * @throws ResponseErrorException
- */
- public function getEvents(EventParameters $params = null): array
- {
- $response = $this->processRequest($params !== null ? $params : new EventParameters());
- $data = $response->getData();
-
- if ($data === null) {
- return [];
- }
-
- return \array_map(Event::class . '::fromResponseData', $data);
- }
-
-
- /**
- * @throws ResponseErrorException
- */
- public function addAttendeeToEvent(EventAttendee $eventAttendee): void
- {
- $eventAttendee->setCredentials($this->username, $this->password);
- $response = $this->httpClient->send($this->createRequest($eventAttendee));
-
- $this->checkForResponseContentType($response);
-
- $domDocument = $this->generateDOM($response);
-
- $this->checkForResponseErrors($domDocument);
- }
-
-
- // organizational units
-
- /**
- * @return OrganizationalUnit[]
- * @throws NotFoundException
- * @throws TransferErrorException
- * @throws ResponseErrorException
- */
- public function getOrganizationalUnits(OrganizationalUnitParameters $params = null): array
- {
- $response = $this->processRequest($params !== null ? $params : new OrganizationalUnitParameters());
-
- $organizationalUnits = [];
- foreach ($response->getData() as $organizationalUnit) {
- try {
- $organizationalUnits[] = OrganizationalUnit::fromResponseData($organizationalUnit);
-
- } catch (UnknownOrganizationUnitTypeException $e) {
- continue; // In case of unknown type - just ignore it.
-
- }
- }
-
- return $organizationalUnits;
- }
-
-
- // adoption
-
- /**
- * @throws ResponseErrorException
- */
- public function saveRequestForAdoption(Adoption $adoption): void
- {
- $adoption->setCredentials($this->username, $this->password);
-
- $response = $this->httpClient->send($this->createRequest($adoption));
-
- $this->checkForResponseContentType($response);
-
- $domDocument = $this->generateDOM($response);
-
- $this->checkForResponseErrors($domDocument);
- }
-
-
- /**
- * @throws NotFoundException
- * @throws TransferErrorException
- * @throws ResponseErrorException
- */
- private function processRequest(Parameters $requestParameters): Response
- {
- $requestParameters->setCredentials($this->username, $this->password);
-
- try {
- $response = $this->httpClient->send($this->createRequest($requestParameters));
-
- } catch (ClientException $e) {
- throw new NotFoundException('Bis client could not find the queried resource.', 0, $e);
-
- } catch (GuzzleException $e) {
- throw new TransferErrorException('Unable to process request: transfer error.', 0, $e);
- }
-
- $this->checkForResponseContentType($response);
-
- $domDocument = $this->generateDOM($response);
- $this->checkForResponseErrors($domDocument);
-
- return new Response($response, $domDocument);
- }
-
-
- /**
- * @throws InvalidContentTypeException
- */
- private function checkForResponseContentType(ResponseInterface $response): void
- {
- if (\strncmp($response->getHeaderLine('Content-Type'), 'text/xml', \strlen('text/xml')) !== 0) {
- throw new InvalidContentTypeException('Unable to process response: the response Content-Type is invalid or missing.');
- }
- }
-
-
- /**
- * @throws InvalidXMLStructureException
- */
- private function generateDOM(ResponseInterface $response): \DOMDocument
- {
- try {
- $domDocument = new \DOMDocument();
- $domDocument->loadXML($response->getBody()->getContents());
-
- } catch (\Exception $e) {
- throw new InvalidXMLStructureException('Unable to process response: response body contains invalid XML.', 0, $e);
- }
-
- return $domDocument;
- }
-
-
- /**
- * @throws ResponseErrorException
- */
- private function checkForResponseErrors(\DOMDocument $domDocument): void
- {
- $resultNode = $domDocument->getElementsByTagName(Response::TAG_RESULT)->item(0);
- \assert($resultNode instanceof \DOMElement);
-
- if ($resultNode->hasAttribute(Response::TAG_RESULT_ATTRIBUTE_ERROR)) {
- switch ($resultNode->getAttribute(Response::TAG_RESULT_ATTRIBUTE_ERROR)) {
- case 'success': // In case of POST request with form data, BIS returns `` for some reason... Let's pretend that there is no error in such case because... you know... there is no error!
- break;
-
- case 'user':
- throw new InvalidUserInputException($resultNode);
-
- case 'forbidden':
- throw new UnauthorizedAccessException();
-
- case 'params':
- throw new InvalidParametersException();
-
- default:
- throw new UnknownErrorException($resultNode->getAttribute(Response::TAG_RESULT_ATTRIBUTE_ERROR));
- }
- }
- }
-
-
- private function createRequest(Parameters $parameters): Request
- {
- return new Request(
- 'POST',
- $this->url,
- [
- 'Content-Type' => 'application/x-www-form-urlencoded',
- ],
- \http_build_query($parameters->getAll())
- );
- }
-
-}
diff --git a/src/Endpoint.php b/src/Endpoint.php
new file mode 100644
index 0000000..83f21d8
--- /dev/null
+++ b/src/Endpoint.php
@@ -0,0 +1,34 @@
+toArray())
+ : '';
+
+ // see Guzzle exceptions docs: https://docs.guzzlephp.org/en/stable/quickstart.html#exceptions
+ try {
+ $response = $this->client->send(new Request(
+ $method,
+ $endpoint . $queryString,
+ [
+ 'Authorization' => 'Bearer ' . $this->authorizationToken->toString(),
+ 'Content-Type' => 'application/json',
+ ],
+ \json_encode($data !== null ? $data->toArray() : []),
+ ));
+
+ } catch (ClientException $e) { // 4xx errors
+ if ($e->getCode() === 400) {
+ throw UnableToProcessRequest::withPrevious($e);
+ }
+
+ if ($e->getCode() === 404) {
+ throw NotFound::withPrevious($e);
+ }
+
+ throw ConnectionToBisFailed::withPrevious($e);
+
+ } catch (ServerException $e) { // 5xx errors
+ throw ConnectionToBisFailed::withPrevious($e);
+
+ } catch (TooManyRedirectsException $e) {
+ throw ConnectionToBisFailed::withPrevious($e);
+
+ } catch (NetworkExceptionInterface $e) { // problem with connection
+ throw ConnectionToBisFailed::withPrevious($e);
+
+ } catch (GuzzleException $e) { // fallback catch-all exception
+ throw ConnectionToBisFailed::withPrevious($e);
+ }
+
+ return \json_decode($response->getBody()->getContents());
+ }
+
+}
diff --git a/src/Request/Adoption.php b/src/Request/Adoption.php
index 9ccc658..6c84ba1 100644
--- a/src/Request/Adoption.php
+++ b/src/Request/Adoption.php
@@ -1,38 +1,34 @@
'adopce',
- 'f_jmeno' => $firstName,
- 'f_prijmeni' => $lastName,
- 'f_ulice' => $streetAddress . ' ' . $streetNumber,
- 'f_mesto' => $city,
- 'f_psc' => $postalCode,
- 'f_email' => $emailAddress,
- 'f_pohlavi' => null, // not required, but accepted by BIS (values muz/zena)
- 'f_uvest_v_seznamu' => $excludeFromPublic ? 'off' : 'on',
- 'f_clanek' => $preferredUnitOfTypeBase,
- 'f_rc' => $preferredUnitOfTypeRegional,
- 'f_castka' => $amount,
- ]);
+ throw new UsageException('This is not implemented yet.');
}
+
+ public function toArray(): array
+ {
+ return [];
+ }
+
+
}
diff --git a/src/Request/Event/EventAttendee.php b/src/Request/Event/EventAttendee.php
new file mode 100644
index 0000000..3973143
--- /dev/null
+++ b/src/Request/Event/EventAttendee.php
@@ -0,0 +1,48 @@
+questionAnswers as $questionAnswer) {
+ $questionAnswers['additional_question_' . $i] = $questionAnswer;
+ $i++;
+ }
+
+ return \array_merge([
+ 'event' => $this->eventId,
+ 'first_name' => $this->firstName,
+ 'last_name' => $this->lastName,
+ 'telephone' => $this->phoneNumber,
+ 'email' => $this->emailAddress,
+ 'age_group' => $this->birthDate->format('Y'),
+ 'birth_month' => $this->birthDate->format('n'),
+ 'birth_day' => $this->birthDate->format('j'),
+ 'note' => $this->note,
+ ], $questionAnswers);
+ }
+
+}
diff --git a/src/Request/Event/EventParameters.php b/src/Request/Event/EventParameters.php
new file mode 100644
index 0000000..65f1def
--- /dev/null
+++ b/src/Request/Event/EventParameters.php
@@ -0,0 +1,176 @@
+orderByDateTo();
+ }
+
+
+
+ // filter
+
+ public const FILTER_ACTIONS_ONLY = 'action';
+ public const FILTER_CAMPS_ONLY = 'camp';
+
+ private string $filter = '';
+
+ public function setFilter($filter): self
+ {
+ if ( ! \in_array($filter, [
+ self::FILTER_ACTIONS_ONLY,
+ self::FILTER_CAMPS_ONLY,
+ ])) {
+ throw new UsageException('Value `' . $filter . '` is not of valid filters');
+ }
+
+ $this->filter = $filter;
+ return $this;
+ }
+
+
+ // type
+
+ /** @var EventType[] */
+ private array $types = [];
+
+ public function setType(EventType $type): self
+ {
+ $this->types = [$type];
+ return $this;
+ }
+
+ /**
+ * @param EventType[] $types
+ */
+ public function setTypes(array $types): self
+ {
+ $this->types = $types;
+ return $this;
+ }
+
+
+ // program
+
+ /** @var Program[] */
+ private array $programs = [];
+
+ public function setProgram(Program $program): self
+ {
+ $this->programs = [$program];
+ return $this;
+ }
+
+ /**
+ * @param Program[] $programs
+ */
+ public function setPrograms(array $programs): self
+ {
+ $this->programs = $programs;
+ return $this;
+ }
+
+
+ // target group
+
+ /** @var TargetGroup[] */
+ private array $targetGroups = [];
+
+ public function setTargetGroup(TargetGroup $targetGroup): self
+ {
+ $this->targetGroups = [$targetGroup];
+ return $this;
+ }
+
+ /**
+ * @param TargetGroup[] $targetGroups
+ */
+ public function setTargetGroups(array $targetGroups): self
+ {
+ $this->targetGroups = $targetGroups;
+ return $this;
+ }
+
+
+
+ // miscellaneous
+
+ private \DateTimeImmutable $dateFromGreaterThan;
+
+ /**
+ * Excludes events which are running (started, but not yet ended). Defaults to include them.
+ */
+ public function excludeRunning(): self
+ {
+ $this->dateFromGreaterThan = new \DateTimeImmutable();
+ return $this;
+ }
+
+
+ public function orderByDateFrom(): self
+ {
+ $this->ordering = Ordering::DATE_FROM();
+ return $this;
+ }
+
+ public function orderByDateTo(): self
+ {
+ $this->ordering = Ordering::DATE_TO();
+ return $this;
+ }
+
+
+ /** @var int[] */
+ private array $organizedBy = [];
+
+ /**
+ * @param int|int[] $unitIds
+ */
+ public function setOrganizedBy(array|int $unitIds): self
+ {
+ // If just single value, wrap it into an array.
+ if ( ! \is_array($unitIds)) {
+ $this->organizedBy = [$unitIds];
+ return $this;
+ }
+
+ $this->organizedBy = $unitIds;
+ return $this;
+ }
+
+
+
+ // getters
+
+ public function toArray(): array
+ {
+ $array = [
+ 'basic_purpose' => $this->filter,
+ 'event_type_array' => \implode(',', $this->types),
+ 'program_array' => \implode(',', $this->programs),
+ 'indended_for_array' => \implode(',', $this->targetGroups),
+ 'ordering' => $this->ordering,
+ 'administrative_unit' => \implode(',', $this->organizedBy),
+ ];
+
+ if (isset($this->dateFromGreaterThan)) {
+ $array['date_from__gte'] = $this->dateFromGreaterThan->format('Y-m-d');
+ }
+
+ return $array;
+ }
+
+}
diff --git a/src/Request/Event/Ordering.php b/src/Request/Event/Ordering.php
new file mode 100644
index 0000000..2666107
--- /dev/null
+++ b/src/Request/Event/Ordering.php
@@ -0,0 +1,19 @@
+ 'prihlaska',
- 'akce' => $eventId,
- 'jmeno' => $firstName,
- 'prijmeni' => $lastName,
- 'telefon' => $phoneNumber,
- 'email' => $emailAddress,
- 'datum_narozeni' => $birthDate,
- 'poznamka' => $note,
- ]);
-
-
- if (\count($questionAnswers) === 0) {
- return;
- }
-
- // currently 3 questions are supported
- $i = 1;
- foreach ($questionAnswers as $questionAnswer) {
- $this->params['add_info' . ($i >= 2 ? '_' . $i : '')] = $questionAnswer; // key syntax is `add_info` for first key and `add_info_X` for any other
- $i++;
- }
- }
-
-}
diff --git a/src/Request/EventParameters.php b/src/Request/EventParameters.php
deleted file mode 100644
index 56e2dd9..0000000
--- a/src/Request/EventParameters.php
+++ /dev/null
@@ -1,304 +0,0 @@
- 'akce',
- self::PARAM_DISPLAY_ALREADY_STARTED_KEY => self::PARAM_DISPLAY_ALREADY_STARTED_VALUE,
- self::PARAM_ORDER_BY_KEY => self::PARAM_ORDER_BY_END_DATE,
- ]);
- }
-
-
- public function setId(int $id): static
- {
- $this->params['id'] = (int) $id;
- return $this;
- }
-
-
- // filter
-
- const FILTER_CLUB = 1;
- const FILTER_WEEKEND = 2;
- const FILTER_CAMP = 4;
- const FILTER_EKOSTAN = 8;
-
- /**
- * This parameter serves as combinator for multiple conditions, which can not be achieved with concatenating type, program, target group or any other available parameters.
- * For example you can not make an union among different parameters. Let's say you want all events which are of type=ohb or of program=brdo. This is not possible with API parameters.
- * Thus you can take advantage of preset filters which are documented here: https://bis.brontosaurus.cz/myr.php
- *
- * Beside standard constant usage as a parameter, you can pass bitwise operation argument, e.g. `EventParameters::FILTER_WEEKEND|EventParameters::FILTER_CAMP`.
- *
- * @throws InvalidArgumentException
- */
- public function setFilter(int $filter): static
- {
- $keys = [
- self::FILTER_CLUB => 'klub',
- self::FILTER_WEEKEND => 'vik',
- self::FILTER_CAMP => 'tabor',
- self::FILTER_EKOSTAN => 'ekostan',
- ];
-
- switch ($filter) {
- case self::FILTER_CLUB:
- case self::FILTER_WEEKEND:
- case self::FILTER_CAMP:
- case self::FILTER_EKOSTAN:
- $param = $keys[$filter];
- break;
-
- case self::FILTER_WEEKEND | self::FILTER_CAMP:
- $param = $keys[self::FILTER_WEEKEND] . $keys[self::FILTER_CAMP];
- break;
-
- case self::FILTER_WEEKEND | self::FILTER_EKOSTAN:
- $param = $keys[self::FILTER_WEEKEND] . $keys[self::FILTER_EKOSTAN];
- break;
-
- default:
- throw new InvalidArgumentException('Value `' . $filter . '` is not of valid types and their combinations for `filter` parameter. Only `weekend+camp` and `weekend+ekostan` can be combined.');
- break;
- }
-
- $this->params['filter'] = $param;
-
- return $this;
- }
-
-
- // type
-
- const TYPE_VOLUNTARY = 'pracovni'; // dobrovolnická
- const TYPE_EXPERIENCE = 'prozitkova'; // zážitková
- const TYPE_SPORT = 'sportovni';
-
- const TYPE_EDUCATIONAL_TALK = 'prednaska'; // vzdělávací - přednášky
- const TYPE_EDUCATIONAL_COURSES = 'vzdelavaci'; // vzdělávací - kurzy, školení
- const TYPE_EDUCATIONAL_OHB = 'ohb'; // vzdělávací - kurz ohb
- const TYPE_LEARNING_PROGRAM = 'vyuka'; // výukový program
- const TYPE_RESIDENTIAL_LEARNING_PROGRAM = 'pobyt'; // pobytový výukový program
-
- const TYPE_CLUB_MEETUP = 'klub'; // klub - setkání
- const TYPE_CLUB_TALK = 'klub-predn'; // klub - přednáška
- const TYPE_FOR_PUBLIC = 'verejnost'; // akce pro veřejnost
- const TYPE_EKOSTAN = 'ekostan';
- const TYPE_EXHIBITION = 'vystava';
- const TYPE_ACTION_GROUP = 'akcni'; // akční skupina
- const TYPE_INTERNAL = 'jina'; // interní akce (VH a jiné)
- const TYPE_GROUP_MEETING = 'schuzka'; // oddílová, družinová schůzka
-
- /**
- * @throws InvalidArgumentException
- */
- public function setType(string $type): static
- {
- if ( ! \in_array($type, [
- self::TYPE_VOLUNTARY,
- self::TYPE_EXPERIENCE,
- self::TYPE_SPORT,
-
- self::TYPE_EDUCATIONAL_TALK,
- self::TYPE_EDUCATIONAL_COURSES,
- self::TYPE_EDUCATIONAL_OHB,
- self::TYPE_LEARNING_PROGRAM,
- self::TYPE_RESIDENTIAL_LEARNING_PROGRAM,
-
- self::TYPE_CLUB_MEETUP,
- self::TYPE_CLUB_TALK,
- self::TYPE_FOR_PUBLIC,
- self::TYPE_EKOSTAN,
- self::TYPE_EXHIBITION,
- self::TYPE_ACTION_GROUP,
- self::TYPE_INTERNAL,
- self::TYPE_GROUP_MEETING,
- ], true)) {
- throw new InvalidArgumentException('Value `' . $type . '` is not of valid types for `type` parameter.');
- }
-
- $this->params['typ'][] = $type;
- return $this;
- }
-
- /**
- * @param string[] $types
- */
- public function setTypes(array $types): static
- {
- foreach ($types as $type) {
- $this->setType($type);
- }
-
- return $this;
- }
-
-
- // program
-
- const PROGRAM_NOT_SELECTED = 'none';
- const PROGRAM_NATURE = 'ap';
- const PROGRAM_SIGHTS = 'pamatky';
- const PROGRAM_BRDO = 'brdo';
- const PROGRAM_EKOSTAN = 'ekostan';
- const PROGRAM_PSB = 'psb';
- const PROGRAM_EDUCATION = 'vzdelavani';
-
- /**
- * @throws InvalidArgumentException
- */
- public function setProgram(string $program): static
- {
- if ( ! \in_array($program, [
- self::PROGRAM_NOT_SELECTED,
- self::PROGRAM_NATURE,
- self::PROGRAM_SIGHTS,
- self::PROGRAM_BRDO,
- self::PROGRAM_EKOSTAN,
- self::PROGRAM_PSB,
- self::PROGRAM_EDUCATION,
- ], true)) {
- throw new InvalidArgumentException('Value `' . $program . '` is not of valid types for `program` parameter.');
- }
-
- $this->params['program'][] = $program;
- return $this;
- }
-
- /**
- * @param string[] $programs
- */
- public function setPrograms(array $programs): static
- {
- foreach ($programs as $program) {
- $this->setProgram($program);
- }
-
- return $this;
- }
-
-
- // target group
-
- const TARGET_GROUP_EVERYONE = 'vsichni';
- const TARGET_GROUP_ADULTS = 'dospeli';
- const TARGET_GROUP_CHILDREN = 'deti';
- const TARGET_GROUP_FAMILIES = 'detirodice';
- const TARGET_GROUP_FIRST_TIME_ATTENDEES = 'prvouc';
-
- /**
- * @throws InvalidArgumentException
- */
- public function setTargetGroup(string $targetGroup): static
- {
- if ( ! \in_array($targetGroup, [
- self::TARGET_GROUP_EVERYONE,
- self::TARGET_GROUP_ADULTS,
- self::TARGET_GROUP_CHILDREN,
- self::TARGET_GROUP_FAMILIES,
- self::TARGET_GROUP_FIRST_TIME_ATTENDEES,
- ], true)) {
- throw new InvalidArgumentException('Value `' . $targetGroup . '` is not of valid types for `for` parameter.');
- }
-
- $this->params['pro'][] = $targetGroup;
- return $this;
- }
-
- /**
- * @param string[] $targetGroups
- */
- public function setTargetGroups(array $targetGroups): static
- {
- foreach ($targetGroups as $targetGroup) {
- $this->setTargetGroup($targetGroup);
- }
-
- return $this;
- }
-
-
- // date constraints
-
- const PARAM_DATE_FORMAT = 'Y-m-d';
-
- public function setFrom(\DateTimeImmutable $dateFrom): static
- {
- $this->params['od'] = $dateFrom->format(self::PARAM_DATE_FORMAT);
- return $this;
- }
-
- public function setUntil(\DateTimeImmutable $dateFrom): static
- {
- $this->params['do'] = $dateFrom->format(self::PARAM_DATE_FORMAT);
- return $this;
- }
-
- public function setYear(int $year): static
- {
- $this->params['rok'] = (int) $year;
- return $this;
- }
-
- public function hideTheseAlreadyStarted(): static
- {
- unset($this->params[self::PARAM_DISPLAY_ALREADY_STARTED_KEY]);
- return $this;
- }
-
-
- // miscellaneous
-
- public function orderByStartDate(): static
- {
- unset($this->params[self::PARAM_ORDER_BY_KEY]);
- return $this;
- }
-
- /**
- * @param int|int[] $unitIds
- */
- public function setOrganizedBy(array|int $unitIds): static
- {
- $organizedByKey = 'zc';
-
- // If just single value, wrap it into an array.
- if ( ! \is_array($unitIds)) {
- $unitIds = [$unitIds];
- }
-
- foreach ($unitIds as $unitId) {
- // If such value is not present yet, initialize it with an empty array.
- if ( ! \is_array($this->params[$organizedByKey])) {
- $this->params[$organizedByKey] = [];
- }
-
- $this->params[$organizedByKey][] = (int) $unitId;
- }
-
- return $this;
- }
-
- public function includeNonPublic(): static
- {
- $this->params['vse'] = 1;
- return $this;
- }
-
-}
diff --git a/src/Request/OrganizationalUnitParameters.php b/src/Request/OrganizationalUnitParameters.php
deleted file mode 100644
index 011bced..0000000
--- a/src/Request/OrganizationalUnitParameters.php
+++ /dev/null
@@ -1,44 +0,0 @@
- 'zc'
- ]);
- }
-
-
- /**
- * @throws InvalidArgumentException
- */
- public function setType(string $type): static
- {
- if (!\in_array($type, [
- self::TYPE_CLUB,
- self::TYPE_BASE,
- self::TYPE_REGIONAL,
- ], true)) {
- throw new InvalidArgumentException('Type `' . $type . '` is not of valid types.');
- }
-
- $this->params[self::PARAM_FILTER] = $type;
-
- return $this;
- }
-
-}
diff --git a/src/Request/Parameters.php b/src/Request/Parameters.php
deleted file mode 100644
index 5fd5b4c..0000000
--- a/src/Request/Parameters.php
+++ /dev/null
@@ -1,51 +0,0 @@
-params = $params;
- }
-
-
- public function getAll(): array
- {
- return $this->params;
- }
-
-
- public function getQueryString(): string
- {
- return \http_build_query($this->params);
- }
-
-
- public function setCredentials(string $username, string $password): static
- {
- $this->params[self::PARAM_USERNAME] = $username;
- $this->params[self::PARAM_PASSWORD] = $password;
-
- return $this;
- }
-
-}
diff --git a/src/Request/ToArray.php b/src/Request/ToArray.php
new file mode 100644
index 0000000..b36e372
--- /dev/null
+++ b/src/Request/ToArray.php
@@ -0,0 +1,11 @@
+latitude;
+ }
+
+
+ public function getLongitude(): float
+ {
+ return $this->longitude;
+ }
+
+}
diff --git a/src/Response/Event/Event.php b/src/Response/Event/Event.php
index 7c37fa9..0e8d41c 100644
--- a/src/Response/Event/Event.php
+++ b/src/Response/Event/Event.php
@@ -1,17 +1,20 @@
contact_person_email;
+ $registrationCustomUrl = $data->entry_form_url;
$registrationQuestions = \array_filter([ // exclude all null items
- $webRegistrationQuestion1,
- $webRegistrationQuestion2,
- $webRegistrationQuestion3,
- ], fn($v, $k) => $v !== null, \ARRAY_FILTER_USE_BOTH);
+ $data->additional_question_1,
+ $data->additional_question_2,
+ $data->additional_question_3,
+ ], fn($v, $k) => $v !== '', \ARRAY_FILTER_USE_BOTH);
$registrationType = RegistrationType::from(
- $registrationType,
+ RegistrationTypeEnum::fromScalar($data->registration_method),
\array_map(fn(string $question) => RegistrationQuestion::from($question), $registrationQuestions),
$contactEmail,
$registrationCustomUrl,
);
- // price
- $price = 0;
- if (isset($data['poplatek']) && $data['poplatek'] !== '') {
- $price = $data['poplatek'];
-
- if (\preg_match('|^[0-9]+$|', $price)) {
- $price = (int) $price;
- }
- }
// organizers
- $organizationalUnitId = (isset($data['porada_id']) && $data['porada_id'] !== '') ? ((int) $data['porada_id']) : null;
- $organizationalUnitName= (isset($data['porada']) && $data['porada'] !== '') ? $data['porada'] : null;
- $organizers = (isset($data['org']) && $data['org'] !== '') ? $data['org'] : null;
- $contactPersonName = (isset($data['kontakt']) && $data['kontakt'] !== '') ? $data['kontakt'] : null;
- $contactPhone = $data['kontakt_telefon'];
- $responsiblePerson = (isset($data['odpovedna']) && $data['odpovedna'] !== '') ? $data['odpovedna'] : null;
+ $organizationalUnitName = $data->administrative_unit_name !== '' ? $data->administrative_unit_name : null;
+ $organizationalUnitWebsite = $data->administrative_unit_web_url !== '' ? $data->administrative_unit_web_url : null;
+ $organizers = $data->looking_forward_to_you !== '' ? $data->looking_forward_to_you : null;
+ $responsiblePerson = $data->responsible_person !== '' ? $data->responsible_person : null;
$organizer = Organizer::from(
- ($organizationalUnitId !== null && $organizationalUnitName !== null)
- ? OrganizerOrganizationalUnit::from($organizationalUnitId, $organizationalUnitName)
+ ($organizationalUnitName !== null)
+ ? OrganizerOrganizationalUnit::from($organizationalUnitName, $organizationalUnitWebsite)
: null,
$responsiblePerson,
$organizers,
- $contactPersonName,
- $contactPhone,
- $contactEmail,
+ ContactPerson::from(
+ $data->contact_person_name,
+ $contactEmail,
+ $data->contact_person_telephone,
+ ),
);
// invitation
- // BIS API returns "0", "1", "2" etc. for real options and "" when nothing is set
- $food = (isset($data['strava']) && $data['strava'] !== '')
- ? Food::fromScalar((int) $data['strava'])
- : Food::NOT_LISTED();
-
/** @var Photo[] $invitationPresentationPhotos */
$invitationPresentationPhotos = [];
for ($i = 1; $i <= 6; $i++) {
- if (isset($data['ochutnavka_' . $i]) && $data['ochutnavka_' . $i] !== '') {
- $invitationPresentationPhotos[] = Photo::from($data['ochutnavka_' . $i]);
+ $photo = $data->{'additional_photo_' . $i};
+ if ($photo !== null) {
+ $invitationPresentationPhotos[] = Photo::from($photo);
}
}
- $invitationOrganizationalInformation = (isset($data['text_info']) && $data['text_info'] !== '') ? $data['text_info'] : ''; // this will not be needed in BIS but now it has to be there as somehow obligatory fields are not required anymore in old BIS
- $invitationIntroduction = (isset($data['text_uvod']) && $data['text_uvod'] !== '') ? $data['text_uvod'] : ''; // this will not be needed in BIS but now it has to be there as somehow obligatory fields are not required anymore in old BIS
- $invitationPresentationText = (isset($data['text_mnam']) && $data['text_mnam'] !== '') ? $data['text_mnam'] : null;
- $invitationWorkDescription = (isset($data['text_dobr']) && $data['text_dobr'] !== '') ? $data['text_dobr'] : null;
- $workHoursPerDay = (isset($data['pracovni_doba']) && $data['pracovni_doba'] !== '') ? ((int) $data['pracovni_doba']) : null;
- $accommodation = (isset($data['ubytovani']) && $data['ubytovani'] !== '') ? $data['ubytovani'] : null;
+ $invitationPresentationText = $data->invitation_text_4;
$invitation = Invitation::from(
- $invitationIntroduction,
- $invitationOrganizationalInformation,
- $accommodation,
- $food,
- $invitationWorkDescription,
- $workHoursPerDay,
+ $data->invitation_text_1,
+ $data->invitation_text_2,
+ $data->accommodation !== '' ? $data->accommodation : null,
+ \array_map(static fn($diet) => Food::fromScalar($diet), $data->diet),
+ $data->invitation_text_3,
+ $data->working_hours,
($invitationPresentationText !== null || \count($invitationPresentationPhotos) > 0)
? Presentation::from($invitationPresentationText, $invitationPresentationPhotos)
: null,
@@ -159,7 +103,7 @@ public static function fromResponseData(array $data): static
// related website
- $relatedWebsite = (isset($data['web']) && $data['web'] !== '') ? $data['web'] : null;
+ $relatedWebsite = $data->web_url;
$_relatedWebsite = null;
if ($relatedWebsite !== null) {
if ( ! self::startsWith($relatedWebsite, 'http')) { // count with no protocol typed URLs
@@ -170,24 +114,34 @@ public static function fromResponseData(array $data): static
}
return new self(
- (int) $data['id'],
- $data['nazev'],
- (isset($data['foto_hlavni']) && $data['foto_hlavni'] !== '') ? $data['foto_hlavni'] : null,
- \DateTimeImmutable::createFromFormat('Y-m-d', $data['od']),
- \DateTimeImmutable::createFromFormat('Y-m-d', $data['do']),
- $data['typ'],
- $program,
- $place,
+ $data->id,
+ $data->name,
+ $data->main_photo,
+ $data->date_from === null
+ ? \DateTimeImmutable::createFromFormat('Y-m-d', '1970-01-01') // todo temp, until there are nullable dates coming from API
+ : \DateTimeImmutable::createFromFormat('Y-m-d', $data->date_from),
+ $data->date_to === null
+ ? \DateTimeImmutable::createFromFormat('Y-m-d', '1970-01-02') // todo temp, until there are nullable dates coming from API
+ : \DateTimeImmutable::createFromFormat('Y-m-d', $data->date_to),
+ Program::fromScalar($data->program),
+ $data->location === null
+ ? Place::from('nezadáno', null) // todo temp, until there are nullable locations coming from API
+ : Place::from(
+ $data->location->name,
+ $data->location->gps_latitude !== null && $data->location->gps_longitude !== null
+ ? Coordinates::from($data->location->gps_latitude, $data->location->gps_longitude)
+ : null,
+ ),
$registrationType,
- (isset($data['vek_od']) && $data['vek_od'] !== '') ? ((int) $data['vek_od']) : null,
- (isset($data['vek_do']) && $data['vek_do'] !== '') ? ((int) $data['vek_do']) : null,
- $price,
+ $data->age_from,
+ $data->age_to,
+ $data->participation_fee !== null ? $data->participation_fee : null,
$organizer,
- TargetGroup::from((int) $data['prokoho']),
+ TargetGroup::fromScalar($data->indended_for),
$invitation,
- (isset($data['sraz']) && $data['sraz'] !== '') ? $data['sraz'] : null,
- (isset($data['popis_programu']) && $data['popis_programu'] !== '') ? $data['popis_programu'] : null,
- (isset($data['jak_se_prihlasit']) && $data['jak_se_prihlasit'] !== '') ? $data['jak_se_prihlasit'] : null,
+ $data->start_date !== null
+ ? new \DateTimeImmutable($data->start_date)
+ : null,
$_relatedWebsite,
);
}
@@ -211,12 +165,6 @@ public function getCoverPhotoPath(): ?string
}
- public function hasCoverPhoto(): bool
- {
- return $this->coverPhotoPath !== null;
- }
-
-
public function getDateFrom(): \DateTimeImmutable
{
return $this->dateFrom;
@@ -229,12 +177,6 @@ public function getDateUntil(): \DateTimeImmutable
}
- public function getType(): string
- {
- return $this->type;
- }
-
-
public function getProgram(): Program
{
return $this->program;
@@ -265,18 +207,12 @@ public function getAgeUntil(): ?int
}
- public function getPrice(): int|string
+ public function getPrice(): ?string
{
return $this->price;
}
- public function isPaid(): bool
- {
- return $this->price !== 0;
- }
-
-
public function getOrganizer(): Organizer
{
return $this->organizer;
@@ -295,33 +231,9 @@ public function getInvitation(): Invitation
}
- public function hasTimeFrom(): bool
- {
- return $this->timeFrom !== null;
- }
-
-
- public function getTimeFrom(): ?string
- {
- return $this->timeFrom;
- }
-
-
- public function getProgramDescription(): ?string
- {
- return $this->programDescription;
- }
-
-
- public function getNotes(): ?string
- {
- return $this->notes;
- }
-
-
- public function hasRelatedWebsite(): bool
+ public function getStartDate(): ?\DateTimeImmutable
{
- return $this->relatedWebsite !== null;
+ return $this->startDate;
}
diff --git a/src/Response/Event/Invitation/Food.php b/src/Response/Event/Invitation/Food.php
index 49a2c3b..cdea814 100644
--- a/src/Response/Event/Invitation/Food.php
+++ b/src/Response/Event/Invitation/Food.php
@@ -1,23 +1,27 @@
accommodation !== null;
- }
-
-
public function getAccommodation(): ?string
{
return $this->accommodation;
}
- public function getFood(): Food
+ /**
+ * @return Food[]
+ */
+ public function getFood(): array
{
return $this->food;
}
@@ -75,24 +78,12 @@ public function getWorkDescription(): ?string
}
- public function areWorkHoursPerDayListed(): bool
- {
- return $this->workHoursPerDay !== null;
- }
-
-
public function getWorkHoursPerDay(): ?int
{
return $this->workHoursPerDay;
}
- public function hasPresentation(): bool
- {
- return $this->presentation !== null;
- }
-
-
public function getPresentation(): ?Presentation
{
return $this->presentation;
diff --git a/src/Response/Event/Invitation/Photo.php b/src/Response/Event/Invitation/Photo.php
index 582c3be..df44878 100644
--- a/src/Response/Event/Invitation/Photo.php
+++ b/src/Response/Event/Invitation/Photo.php
@@ -1,6 +1,6 @@
text !== null;
- }
-
-
public function getText(): ?string
{
return $this->text;
}
- public function hasAnyPhotos(): bool
- {
- return \count($this->photos) > 0;
- }
-
/**
* @return Photo[]
*/
diff --git a/src/Response/Event/Organizer/ContactPerson.php b/src/Response/Event/Organizer/ContactPerson.php
new file mode 100644
index 0000000..b8cb186
--- /dev/null
+++ b/src/Response/Event/Organizer/ContactPerson.php
@@ -0,0 +1,43 @@
+name;
+ }
+
+
+ public function getEmailAddress(): string
+ {
+ return $this->emailAddress;
+ }
+
+
+ public function getPhoneNumber(): string
+ {
+ return $this->phoneNumber;
+ }
+
+}
diff --git a/src/Response/Event/Organizer.php b/src/Response/Event/Organizer/Organizer.php
similarity index 54%
rename from src/Response/Event/Organizer.php
rename to src/Response/Event/Organizer/Organizer.php
index 7c4c436..454802a 100644
--- a/src/Response/Event/Organizer.php
+++ b/src/Response/Event/Organizer/Organizer.php
@@ -1,6 +1,6 @@
organizers !== null;
- }
-
-
public function getOrganizers(): ?string
{
return $this->organizers;
}
- public function getContactPersonName(): ?string
- {
- return $this->contactPersonName;
- }
-
-
- public function getContactPhone(): string
- {
- return $this->contactPhone;
- }
-
-
- public function getContactEmail(): string
+ public function getContactPerson(): ContactPerson
{
- return $this->contactEmail;
+ return $this->contactPerson;
}
}
diff --git a/src/Response/Event/Organizer/OrganizerOrganizationalUnit.php b/src/Response/Event/Organizer/OrganizerOrganizationalUnit.php
new file mode 100644
index 0000000..0564d57
--- /dev/null
+++ b/src/Response/Event/Organizer/OrganizerOrganizationalUnit.php
@@ -0,0 +1,32 @@
+name;
+ }
+
+
+ public function getWebsite(): ?string
+ {
+ return $this->website;
+ }
+
+}
diff --git a/src/Response/Event/OrganizerOrganizationalUnit.php b/src/Response/Event/OrganizerOrganizationalUnit.php
deleted file mode 100644
index b94883a..0000000
--- a/src/Response/Event/OrganizerOrganizationalUnit.php
+++ /dev/null
@@ -1,37 +0,0 @@
-id;
- }
-
-
- public function getName(): string
- {
- return $this->name;
- }
-
-}
diff --git a/src/Response/Event/Place.php b/src/Response/Event/Place.php
index 7cdc0ae..c625757 100644
--- a/src/Response/Event/Place.php
+++ b/src/Response/Event/Place.php
@@ -1,6 +1,8 @@
coordinates !== null;
- }
-
-
- public function getCoordinates(): ?string
+ public function getCoordinates(): ?Coordinates
{
return $this->coordinates;
}
diff --git a/src/Response/Event/Program.php b/src/Response/Event/Program.php
deleted file mode 100644
index cbf4746..0000000
--- a/src/Response/Event/Program.php
+++ /dev/null
@@ -1,77 +0,0 @@
-slug->toScalar();
- }
-
-
- public function getName(): ?string
- {
- return $this->name;
- }
-
-
- public function isNotSelected(): bool
- {
- return $this->slug->equals(ProgramType::NONE());
- }
-
-
- public function isOfTypeNature(): bool
- {
- return $this->slug->equals(ProgramType::NATURE());
- }
-
-
- public function isOfTypeSights(): bool
- {
- return $this->slug->equals(ProgramType::SIGHTS());
- }
-
-
- public function isOfTypeBrdo(): bool
- {
- return $this->slug->equals(ProgramType::BRDO());
- }
-
-
- public function isOfTypeEkostan(): bool
- {
- return $this->slug->equals(ProgramType::EKOSTAN());
- }
-
-
- public function isOfTypePsb(): bool
- {
- return $this->slug->equals(ProgramType::PSB());
- }
-
-
- public function isOfTypeEducation(): bool
- {
- return $this->slug->equals(ProgramType::EDUCATION());
- }
-
-}
diff --git a/src/Response/Event/ProgramType.php b/src/Response/Event/ProgramType.php
deleted file mode 100644
index df29adf..0000000
--- a/src/Response/Event/ProgramType.php
+++ /dev/null
@@ -1,29 +0,0 @@
-hasValidData = match (true) {
- $type->equals(RegistrationTypeEnum::EMAIL()) && $email === null,
- $type->equals(RegistrationTypeEnum::EXTERNAL_WEBPAGE()) && $url === null,
- => false,
- default => true
- };
- }
+ ) {}
/**
* @param RegistrationQuestion[] $questions
@@ -51,11 +41,6 @@ public function isOfTypeBrontoWeb(): bool
}
- public function areAnyQuestions(): bool
- {
- return \count($this->questions) > 0;
- }
-
/**
* @return RegistrationQuestion[]
*/
@@ -72,18 +57,19 @@ public function isOfTypeEmail(): bool
return $this->type->equals(RegistrationTypeEnum::EMAIL());
}
- /**
- * @throws RegistrationTypeException
- * @throws BadUsageException
- */
public function getEmail(): ?string
{
- if ( ! $this->hasValidData()) {
- throw RegistrationTypeException::missingAdditionalData('email', $this->type);
+ if ( ! $this->isOfTypeEmail()) {
+ throw new UsageException('This method can not be called when the registration is not of `via e-mail` type.');
}
- if ( ! $this->isOfTypeEmail()) {
- throw new BadUsageException('This method can not be called when the registration is not of `via e-mail` type.');
+ if ($this->email === null) {
+ /*
+ * Ideally, this should not happen, but we can not rely on it. If it happens, we want to know about it ->
+ * assert() is not enough. We can just log it, but that would lead user into clicking a button which does nothing.
+ * Thus rendering error page covers both – logging and preventing user from accessing non-working page.
+ */
+ throw new RuntimeException('E-mail must not be null in case of registration via e-mail.');
}
return $this->email;
@@ -97,18 +83,19 @@ public function isOfTypeCustomWebpage(): bool
return $this->type->equals(RegistrationTypeEnum::EXTERNAL_WEBPAGE());
}
- /**
- * @throws RegistrationTypeException
- * @throws BadUsageException
- */
public function getUrl(): ?string
{
- if ( ! $this->hasValidData()) {
- throw RegistrationTypeException::missingAdditionalData('url', $this->type);
+ if ( ! $this->isOfTypeCustomWebpage()) {
+ throw new UsageException('This method can not be called when the registration is not of `via custom webpage` type.');
}
- if ( ! $this->isOfTypeCustomWebpage()) {
- throw new BadUsageException('This method can not be called when the registration is not of `via custom webpage` type.');
+ if ($this->url === null) {
+ /*
+ * Ideally, this should not happen, but we can not rely on it. If it happens, we want to know about it ->
+ * assert() is not enough. We can just log it, but that would lead user into clicking a button which does nothing.
+ * Thus rendering error page covers both – logging and preventing user from accessing non-working page.
+ */
+ throw new RuntimeException('URL must not be null in case of registration via custom webpage.');
}
return $this->url;
@@ -130,10 +117,4 @@ public function isOfTypeDisabled(): bool
return $this->type->equals(RegistrationTypeEnum::DISABLED());
}
-
- public function hasValidData(): bool
- {
- return $this->hasValidData;
- }
-
}
diff --git a/src/Response/Event/Registration/RegistrationTypeEnum.php b/src/Response/Event/Registration/RegistrationTypeEnum.php
index a974aa5..8966b69 100644
--- a/src/Response/Event/Registration/RegistrationTypeEnum.php
+++ b/src/Response/Event/Registration/RegistrationTypeEnum.php
@@ -1,6 +1,6 @@
id = $id;
- }
-
-
- public static function from(int $id): self
- {
- return new self($id);
- }
-
-
-
- public function isOfTypeEveryone(): bool
- {
- return $this->id === self::EVERYONE;
- }
-
-
- public function isOfTypeAdults(): bool
- {
- return $this->id === self::ADULTS;
- }
-
-
- public function isOfTypeChildren(): bool
- {
- return $this->id === self::CHILDREN;
- }
-
-
- public function isOfTypeFamilies(): bool
- {
- return $this->id === self::FAMILIES;
- }
-
-
- public function isOfTypeFirstTimeAttendees(): bool
- {
- return $this->id === self::FIRST_TIME_ATTENDEES;
- }
-
-}
diff --git a/src/Response/OrganizationalUnit/OrganizationalUnit.php b/src/Response/OrganizationalUnit/OrganizationalUnit.php
index a34f044..7da0386 100644
--- a/src/Response/OrganizationalUnit/OrganizationalUnit.php
+++ b/src/Response/OrganizationalUnit/OrganizationalUnit.php
@@ -1,8 +1,8 @@
id,
+ $data->name,
+ $data->street,
+ $data->city,
+ $data->zip_code,
+ $data->gps_latitude !== null && $data->gps_longitude !== null
+ ? Coordinates::from($data->gps_latitude, $data->gps_longitude)
+ : null,
+ $data->telephone,
+ $data->from_email_address,
+ $data->web_url,
+ OrganizationalUnitType::fromScalar($data->level),
+ $data->president_name,
+ $data->manager_name,
);
}
@@ -82,13 +75,19 @@ public function getPostCode(): string
}
- public function getPhone(): ?string
+ public function getCoordinates(): ?Coordinates
+ {
+ return $this->coordinates;
+ }
+
+
+ public function getPhone(): string
{
return $this->phone;
}
- public function getEmail(): ?string
+ public function getEmail(): string
{
return $this->email;
}
@@ -100,13 +99,13 @@ public function getWebsite(): ?string
}
- public function getChairman(): ?string
+ public function getChairman(): string
{
return $this->chairman;
}
- public function getManager(): ?string
+ public function getManager(): string
{
return $this->manager;
}
diff --git a/src/Response/OrganizationalUnit/OrganizationalUnitType.php b/src/Response/OrganizationalUnit/OrganizationalUnitType.php
index e294b73..617bf63 100644
--- a/src/Response/OrganizationalUnit/OrganizationalUnitType.php
+++ b/src/Response/OrganizationalUnit/OrganizationalUnitType.php
@@ -1,6 +1,6 @@
httpResponse = $httpResponse;
-
- $this->parseDom($domDocument);
- }
-
-
- private function parseDom(\DOMDocument $domDocument): void
- {
- $domFinder = new \DOMXPath($domDocument);
- $rowNodeList = $domFinder->query('*', $domDocument->getElementsByTagName(self::TAG_RESULT)->item(0));
-
- $this->data = [];
- foreach ($rowNodeList as $rowNode) {
- \assert($rowNode instanceof \DOMElement);
-
- $row = [];
- foreach ($domFinder->query('*', $rowNode) as $node) {
- \assert($node instanceof \DOMElement);
-
- // if there is an ID attribute, use this one a the value as it is numeric representation (thus more technically reliable) of element's content
- $row[$node->nodeName] = $node->hasAttribute(self::TAG_ATTRIBUTE_ID) ?
- $node->getAttribute(self::TAG_ATTRIBUTE_ID)
- :
- $node->nodeValue;
- }
-
- $this->data[] = $row;
- }
- }
-
-
- public function getHttpResponse(): ResponseInterface
- {
- return $this->httpResponse;
- }
-
-
- public function getData(): array
- {
- return $this->data;
- }
-
-}
diff --git a/src/Response/exceptions.php b/src/Response/exceptions.php
deleted file mode 100644
index a08b202..0000000
--- a/src/Response/exceptions.php
+++ /dev/null
@@ -1,70 +0,0 @@
-nodeValue);
- }
-
-}
-
-final class UnauthorizedAccessException extends ResponseErrorException
-{
-
- public function __construct()
- {
- parent::__construct('You are not authorized to make such request with given credentials. Or you have simply wrong credentials. :-)');
- }
-
-}
-
-final class UnknownErrorException extends ResponseErrorException
-{
-
- /**
- * @param string $unknownErrorTypeKey
- */
- public function __construct($unknownErrorTypeKey)
- {
- parent::__construct('Unknown error. Error type returned from BIS: ' . $unknownErrorTypeKey);
- }
-
-}
-
-final class RegistrationTypeException extends ResponseErrorException
-{
-
- public static function missingAdditionalData($key, $type)
- {
- return new self(\sprintf('Missing additional data `%s` for selected type %d.', $key, $type));
- }
-
-}
diff --git a/src/exceptions.php b/src/exceptions.php
index d9e64d9..b3605ae 100644
--- a/src/exceptions.php
+++ b/src/exceptions.php
@@ -1,33 +1,54 @@
getMessage(), 0, $previous);
+ }
+}
+
+final class UnableToAuthorize extends BisClientRuntimeException
+{
+ public static function withPrevious(\Throwable $previous): self
+ {
+ return new self("You are not authorized to make such request with given secrets.\nCheck that you passed correct secrets or that you have access to the resource you requested.", 0, $previous);
+ }
+}
+
+final class NotFound extends BisClientRuntimeException
+{
+ public static function withPrevious(\Throwable $previous): self
+ {
+ return new self('The target you requested was not found. Check again that you\'ve typed correct URL or that the resource exists.', 0, $previous);
+ }
+}
+final class ConnectionToBisFailed extends BisClientRuntimeException
+{
+ public static function withPrevious(\Throwable $previous): self
+ {
+ return new self($previous->getMessage(), 0, $previous);
+ }
+}
diff --git a/tests/.gitignore b/tests/.gitignore
new file mode 100644
index 0000000..d8dd038
--- /dev/null
+++ b/tests/.gitignore
@@ -0,0 +1 @@
+secret.php
diff --git a/tests/bootstrap.php b/tests/bootstrap.php
new file mode 100644
index 0000000..3ab7d73
--- /dev/null
+++ b/tests/bootstrap.php
@@ -0,0 +1,22 @@
+ $apiUrl, 'clientId' => $clientId, 'clientSecret' => $clientSecret] = $secret;
+
+ return (new BisClientFactory(
+ $apiUrl,
+ $clientId,
+ $clientSecret,
+ ))->create();
+})();
diff --git a/tests/index.php b/tests/index.php
new file mode 100644
index 0000000..46cf922
--- /dev/null
+++ b/tests/index.php
@@ -0,0 +1,55 @@
+addAttendee(new EventAttendee(
+ $eventId,
+ 'Jan',
+ 'Novák',
+ DateTimeImmutable::createFromFormat('Y-m-d', '2000-05-01'),
+ '123 456 789',
+ 'jan.novak@example.com',
+ 'prosím, abych tam měl nachystanou teplou peřinu',
+ ['odpověď č. 1', '', 'odpověď č. 3'],
+ ));
+};
+// uncomment if you need to test it otherwise it would post on every page load
+//$addAttendee(eventId: 9513); // ⚠ do not forget to customize event id not to pollute real events with testing data
+//exit;
+// -----------------------------
+// retrieving information test
+// -----------------------------
+
+echo '
';
+
+ echo '
';
+ echo '
Event
';
+ dump($client->getEvent(13063));
+ echo '';
+
+ echo '
';
+ echo '
Events
';
+
+ foreach ($client->getEvents() as $event) {
+ dump($event);
+ }
+ echo '';
+
+ echo '
';
+ echo '
Organizational units
';
+
+ foreach ($client->getOrganizationalUnits() as $unit) {
+ dump($unit);
+ }
+ echo '';
+
+echo '
';
diff --git a/tests/secret.template.php b/tests/secret.template.php
new file mode 100644
index 0000000..dcafece
--- /dev/null
+++ b/tests/secret.template.php
@@ -0,0 +1,7 @@
+ '',
+ 'clientId' => '',
+ 'clientSecret' => '',
+];