diff --git a/composer.json b/composer.json index afd365a..24ae02e 100644 --- a/composer.json +++ b/composer.json @@ -11,6 +11,7 @@ "minimum-stability": "stable", "require": { "php": ">=5.6", + "ext-dom": "*", "guzzlehttp/guzzle": "^6.3" }, "require-dev": { @@ -20,7 +21,11 @@ "psr-4": { "HnutiBrontosaurus\\BisApiClient\\": "src/" }, - "classmap": ["src/exceptions.php"] + "classmap": [ + "src/exceptions.php", + "src/Response/exceptions.php", + "src/Response/OrganizationalUnit/exceptions.php" + ] }, "config": { "sort-packages": true diff --git a/src/Client.php b/src/Client.php index 7cc5c11..02a0951 100644 --- a/src/Client.php +++ b/src/Client.php @@ -5,14 +5,24 @@ use GuzzleHttp\Client as HttpClient; use GuzzleHttp\Exception\ClientException; use GuzzleHttp\Exception\GuzzleException; -use GuzzleHttp\Exception\TransferException; use GuzzleHttp\Psr7\Request; +use HnutiBrontosaurus\BisApiClient\Request\Adoption; +use HnutiBrontosaurus\BisApiClient\Request\EventAttendee; use HnutiBrontosaurus\BisApiClient\Request\EventParameters; use HnutiBrontosaurus\BisApiClient\Request\OrganizationalUnitParameters; use HnutiBrontosaurus\BisApiClient\Request\Parameters; -use HnutiBrontosaurus\BisApiClient\Response\Event; -use HnutiBrontosaurus\BisApiClient\Response\OrganizationalUnit; +use HnutiBrontosaurus\BisApiClient\Response\Event\Event; +use HnutiBrontosaurus\BisApiClient\Response\InvalidContentTypeException; +use HnutiBrontosaurus\BisApiClient\Response\InvalidParametersException; +use HnutiBrontosaurus\BisApiClient\Response\InvalidUserInputException; +use HnutiBrontosaurus\BisApiClient\Response\InvalidXMLStructureException; +use HnutiBrontosaurus\BisApiClient\Response\OrganizationalUnit\OrganizationalUnit; +use HnutiBrontosaurus\BisApiClient\Response\OrganizationalUnit\UnknownOrganizationUnitTypeException; use HnutiBrontosaurus\BisApiClient\Response\Response; +use HnutiBrontosaurus\BisApiClient\Response\ResponseErrorException; +use HnutiBrontosaurus\BisApiClient\Response\UnauthorizedAccessException; +use HnutiBrontosaurus\BisApiClient\Response\UnknownErrorException; +use Psr\Http\Message\ResponseInterface; final class Client @@ -36,6 +46,7 @@ final class Client * @param string $username * @param string $password * @param HttpClient $httpClient + * @throws InvalidArgumentException */ public function __construct($url, $username, $password, HttpClient $httpClient) { @@ -56,24 +67,26 @@ public function __construct($url, $username, $password, HttpClient $httpClient) } + // events + /** * @param int $id * @param EventParameters $params * @return Event - * @throws BisClientException - * @throws GuzzleException - * @throws ResourceNotFoundException + * @throws NotFoundException + * @throws TransferErrorException + * @throws ResponseErrorException */ - public function getEvent($id, EventParameters $params = NULL) + public function getEvent($id, EventParameters $params = null) { - $params = ($params !== NULL ? $params : new EventParameters()); + $params = ($params !== null ? $params : new EventParameters()); $params->setId($id); $response = $this->processRequest($params); $data = $response->getData(); if (\count($data) === 0) { - throw new BisClientException('No result for event with id `' . $id . '`.'); + throw new NotFoundException('No result for event with id `' . $id . '`.'); } return Event::fromResponseData(\reset($data)); @@ -82,99 +95,192 @@ public function getEvent($id, EventParameters $params = NULL) /** * @param EventParameters $params * @return Event[] - * @throws BisClientException - * @throws GuzzleException - * @throws ResourceNotFoundException + * @throws NotFoundException + * @throws TransferErrorException + * @throws ResponseErrorException */ - public function getEvents(EventParameters $params = NULL) + public function getEvents(EventParameters $params = null) { - $response = $this->processRequest($params !== NULL ? $params : new EventParameters()); + $response = $this->processRequest($params !== null ? $params : new EventParameters()); $data = $response->getData(); - if ($data === NULL) { + if ($data === null) { return []; } return \array_map(Event::class . '::fromResponseData', $data); } + /** + * @param EventAttendee $eventAttendee + * @throws ResponseErrorException + */ + public function addAttendeeToEvent(EventAttendee $eventAttendee) + { + $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 + /** * @param OrganizationalUnitParameters $params * @return OrganizationalUnit[] - * @throws BisClientException - * @throws GuzzleException - * @throws ResourceNotFoundException + * @throws NotFoundException + * @throws TransferErrorException + * @throws ResponseErrorException */ - public function getOrganizationalUnits(OrganizationalUnitParameters $params = NULL) + public function getOrganizationalUnits(OrganizationalUnitParameters $params = null) { - $response = $this->processRequest($params !== NULL ? $params : new OrganizationalUnitParameters()); - return \array_map(OrganizationalUnit::class . '::fromResponseData', $response->getData()); + $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 + + /** + * @param Adoption $adoption + * @throws ResponseErrorException + */ + public function saveRequestForAdoption(Adoption $adoption) + { + $adoption->setCredentials($this->username, $this->password); + + $response = $this->httpClient->send($this->createRequest($adoption)); + + $this->checkForResponseContentType($response); + + $domDocument = $this->generateDOM($response); + + $this->checkForResponseErrors($domDocument); } /** * @param Parameters $requestParameters * @return Response - * @throws BisClientException - * @throws GuzzleException - * @throws ResourceNotFoundException + * @throws NotFoundException + * @throws TransferErrorException + * @throws ResponseErrorException */ private function processRequest(Parameters $requestParameters) { $requestParameters->setCredentials($this->username, $this->password); - $httpRequest = new Request('POST', $this->buildUrl($requestParameters)); - try { - $response = $this->httpClient->send($httpRequest); + $response = $this->httpClient->send($this->createRequest($requestParameters)); } catch (ClientException $e) { - throw new ResourceNotFoundException('Bis client could not find the queried resource.', 0, $e); + throw new NotFoundException('Bis client could not find the queried resource.', 0, $e); - } catch (TransferException $e) { - throw new BisClientException('Unable to process request: transfer error.', 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); + } + + + /** + * @param ResponseInterface $response + * @throws InvalidContentTypeException + */ + private function checkForResponseContentType(ResponseInterface $response) + { if (\strncmp($response->getHeaderLine('Content-Type'), 'text/xml', \strlen('text/xml')) !== 0) { - throw new BisClientException('Unable to process response: the response Content-Type is invalid or missing.'); + throw new InvalidContentTypeException('Unable to process response: the response Content-Type is invalid or missing.'); } + } + /** + * @param ResponseInterface $response + * @return \DOMDocument + * @throws InvalidXMLStructureException + */ + private function generateDOM(ResponseInterface $response) + { try { $domDocument = new \DOMDocument(); $domDocument->loadXML($response->getBody()); } catch (\Exception $e) { - throw new BisClientException('Unable to process response: response body contains invalid XML.', 0, $e); + throw new InvalidXMLStructureException('Unable to process response: response body contains invalid XML.', 0, $e); } + return $domDocument; + } + + /** + * @param \DOMDocument $domDocument + * @throws ResponseErrorException + */ + private function checkForResponseErrors(\DOMDocument $domDocument) + { $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); + break; + case 'forbidden': - throw new BisClientException('You are not authorized to make such request with given credentials. Or you have simply wrong credentials. :-)'); + throw new UnauthorizedAccessException(); break; case 'params': - throw new BisClientException('Parameters are invalid.'); + throw new InvalidParametersException(); break; default: - throw new BisClientException('Unknown error. Error type returned from BIS: `' . $resultNode->getAttribute(Response::TAG_RESULT_ATTRIBUTE_ERROR) . '`'); + throw new UnknownErrorException($resultNode->getAttribute(Response::TAG_RESULT_ATTRIBUTE_ERROR)); break; } } - - return new Response($response, $domDocument); } /** - * @param Parameters $params - * @return string + * @return Request */ - private function buildUrl(Parameters $params) + private function createRequest(Parameters $parameters) { - $queryString = $params->getQueryString(); - return $this->url . ($queryString !== '' ? '?' . $queryString : ''); + return new Request( + 'POST', + $this->url, + [ + 'Content-Type' => 'application/x-www-form-urlencoded', + ], + \http_build_query($parameters->getAll()) + ); } } diff --git a/src/Request/Adoption.php b/src/Request/Adoption.php new file mode 100644 index 0000000..6bf0a87 --- /dev/null +++ b/src/Request/Adoption.php @@ -0,0 +1,51 @@ + '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, + ]); + } + +} diff --git a/src/Request/EventAttendee.php b/src/Request/EventAttendee.php new file mode 100644 index 0000000..e1e0bdd --- /dev/null +++ b/src/Request/EventAttendee.php @@ -0,0 +1,53 @@ + '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 index f03d707..3046bb7 100644 --- a/src/Request/EventParameters.php +++ b/src/Request/EventParameters.php @@ -8,39 +8,10 @@ final class EventParameters extends Parameters { - const FILTER_CLUB = 1; - const FILTER_WEEKEND = 2; - const FILTER_CAMP = 4; - const FILTER_EKOSTAN = 8; - - const TYPE_WORK = 'pracovni'; - const TYPE_EXPERIENCE = 'prozitkova'; - const TYPE_SPORT = 'sportovni'; - const TYPE_EDUCATIONAL = 'vzdelavaci'; - const TYPE_COURSE = 'prednaska'; - const TYPE_PUBLIC = 'verejnost'; - const TYPE_CLUB = 'klub'; - const TYPE_OHB = 'ohb'; - - const PROGRAM_NATURE = 'ap'; - const PROGRAM_SIGHTS = 'pamatky'; - const PROGRAM_BRDO = 'brdo'; - const PROGRAM_EKOSTAN = 'ekostan'; - const PROGRAM_PSB = 'psb'; - const PROGRAM_EDUCATION = 'vzdelavani'; - - const FOR_ADULTS = 'dospeli'; - const FOR_CHILDREN = 'deti'; - const FOR_FAMILIES = 'detirodice'; - - const PARAM_DATE_FORMAT = 'Y-m-d'; - - const PARAM_DISPLAY_ALREADY_STARTED_KEY = 'aktualni'; - const PARAM_DISPLAY_ALREADY_STARTED_NO = 'od'; - const PARAM_DISPLAY_ALREADY_STARTED_YES = 'do'; + const PARAM_DISPLAY_ALREADY_STARTED_KEY = 'probihajici'; // for default just omit this parameter + const PARAM_DISPLAY_ALREADY_STARTED_VALUE = ''; // whatever value - const PARAM_ORDER_BY_KEY = 'razeni'; - const PARAM_ORDER_BY_START_DATE = 'od'; + const PARAM_ORDER_BY_KEY = 'sort'; // for default sorting just omit this parameter const PARAM_ORDER_BY_END_DATE = 'do'; @@ -48,7 +19,7 @@ public function __construct() { parent::__construct([ self::PARAM_QUERY => 'akce', - self::PARAM_DISPLAY_ALREADY_STARTED_KEY => self::PARAM_DISPLAY_ALREADY_STARTED_YES, + self::PARAM_DISPLAY_ALREADY_STARTED_KEY => self::PARAM_DISPLAY_ALREADY_STARTED_VALUE, self::PARAM_ORDER_BY_KEY => self::PARAM_ORDER_BY_END_DATE, ]); } @@ -64,10 +35,24 @@ public function setId($id) return $this; } + + // filter + + const FILTER_CLUB = 1; + const FILTER_WEEKEND = 2; + const FILTER_CAMP = 4; + const FILTER_EKOSTAN = 8; + /** - * Beside standard constant usage as a paramer, you can pass bitwise operation argument, e.g. `EventParameters::FILTER_WEEKEND|EventParameters::FILTER_CAMP`. + * 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`. + * * @param int $filter * @return self + * @throws InvalidArgumentException */ public function setFilter($filter) { @@ -104,22 +89,55 @@ public function setFilter($filter) 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 + /** * @param string $type * @return self + * @throws InvalidArgumentException */ public function setType($type) { - if (!\in_array($type, [ - self::TYPE_WORK, + if ( ! \in_array($type, [ + self::TYPE_VOLUNTARY, self::TYPE_EXPERIENCE, self::TYPE_SPORT, - self::TYPE_EDUCATIONAL, - self::TYPE_COURSE, - self::TYPE_PUBLIC, - self::TYPE_CLUB, - self::TYPE_OHB, - ], TRUE)) { + + 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.'); } @@ -140,20 +158,33 @@ public function setTypes(array $types) 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'; + /** * @param string $program * @return self + * @throws InvalidArgumentException */ public function setProgram($program) { - if (!\in_array($program, [ + 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)) { + ], true)) { throw new InvalidArgumentException('Value `' . $program . '` is not of valid types for `program` parameter.'); } @@ -174,49 +205,54 @@ public function setPrograms(array $programs) 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'; + /** - * @param string $for + * @param string $targetGroup * @return self + * @throws InvalidArgumentException */ - public function setFor($for) + public function setTargetGroup($targetGroup) { - if (!\in_array($for, [ - self::FOR_ADULTS, - self::FOR_CHILDREN, - self::FOR_FAMILIES, - ], TRUE)) { - throw new InvalidArgumentException('Value `' . $for . '` is not of valid types for `for` parameter.'); + 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'] = $for; + $this->params['pro'][] = $targetGroup; return $this; } /** - * @param int|int[] $unitIds + * @param string[] $targetGroups * @return self */ - public function setOrganizedBy($unitIds) + public function setTargetGroups(array $targetGroups) { - $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; + foreach ($targetGroups as $targetGroup) { + $this->setTargetGroup($targetGroup); } return $this; } + + // date constraints + + const PARAM_DATE_FORMAT = 'Y-m-d'; + /** * @param \DateTimeImmutable $dateFrom * @return self @@ -252,16 +288,44 @@ public function setYear($year) */ public function hideTheseAlreadyStarted() { - $this->params[self::PARAM_DISPLAY_ALREADY_STARTED_KEY] = self::PARAM_DISPLAY_ALREADY_STARTED_NO; + unset($this->params[self::PARAM_DISPLAY_ALREADY_STARTED_KEY]); return $this; } + + // miscellaneous + /** * @return self */ public function orderByStartDate() { - $this->params[self::PARAM_ORDER_BY_KEY] = self::PARAM_ORDER_BY_START_DATE; + unset($this->params[self::PARAM_ORDER_BY_KEY]); + return $this; + } + + /** + * @param int|int[] $unitIds + * @return self + */ + public function setOrganizedBy($unitIds) + { + $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; } diff --git a/src/Request/OrganizationalUnitParameters.php b/src/Request/OrganizationalUnitParameters.php index bd544e1..4a0c339 100644 --- a/src/Request/OrganizationalUnitParameters.php +++ b/src/Request/OrganizationalUnitParameters.php @@ -25,6 +25,8 @@ public function __construct() /** * @param string $type + * @return self + * @throws InvalidArgumentException */ public function setType($type) { @@ -32,11 +34,13 @@ public function setType($type) self::TYPE_CLUB, self::TYPE_BASE, self::TYPE_REGIONAL, - ], TRUE)) { + ], 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 index 0df7395..d8c63d8 100644 --- a/src/Request/Parameters.php +++ b/src/Request/Parameters.php @@ -1,7 +1,7 @@ id = $id; - $this->name = $name; - $this->dateFrom = $dateFrom; - $this->dateUntil = $dateUntil; - $this->type = $type; - $this->place = new Place($placeId, $placeName, $mapLinkOrCoords); - $this->ageFrom = $ageFrom; - $this->ageUntil = $ageUntil; - $this->price = $price; - $this->invitationText = $invitationText; - $this->workDescription = $workDescription; - $this->meetingInformation = $meetingInformation; - $this->workingTime = $workingTime; - $this->programDescription = $programDescription; - $this->accommodation = $accommodation; - $this->food = $food; - $this->notes = $notes; - - - // program - - if ($programSlug !== NULL && $programName !== NULL) { - $this->program = new Program($programSlug, $programName); - } - - - // web registration - - $this->enableWebRegistration = $enableWebRegistration; - - $this->webRegistrationQuestions = \array_map(function ($webRegistrationQuestion) { // And then turn the rest into objects. - return new RegistrationQuestion($webRegistrationQuestion); - }, \array_filter([ // First exclude all null items. - $webRegistrationQuestion1, - $webRegistrationQuestion2, - $webRegistrationQuestion3, - ], function ($v, $k) { - return $v !== NULL; - }, ARRAY_FILTER_USE_BOTH)); - - - // organizers - - $this->organizer = new Organizer( - ($organizationalUnitId !== NULL && $organizationalUnitName !== NULL) ? new OrganizerOrganizationalUnit($organizationalUnitId, $organizationalUnitName) : NULL, - $responsiblePerson, - $organizers, - $contactPersonName, - $contactPhone, - $contactEmail, - $contactWebsite - ); - - - // attachments - - if ($attachment1 !== NULL) { - $this->attachments[] = $attachment1; - } - if ($attachment2 !== NULL) { - $this->attachments[] = $attachment2; - } - } - - - public static function fromResponseData(array $data) - { - $price = NULL; - if ($data['poplatek'] !== '') { - $price = $data['poplatek']; - - if (\preg_match('|^[0-9]+$|', $price)) { - $price = (int)$price; - } - } - - return new self( - (int)$data['id'], - $data['nazev'], - \DateTimeImmutable::createFromFormat('Y-m-d', $data['od']), - \DateTimeImmutable::createFromFormat('Y-m-d', $data['do']), - $data['typ'], - $data['program_id'] !== '' ? $data['program_id'] : NULL, - $data['program'] !== '' ? $data['program'] : NULL, - $data['lokalita_id'] !== '' ? ((int)$data['lokalita_id']) : NULL, - $data['lokalita'], - $data['add_info_title'] !== '' ? $data['add_info_title'] : NULL, - $data['add_info_title_2'] !== '' ? $data['add_info_title_2'] : NULL, - $data['add_info_title_3'] !== '' ? $data['add_info_title_3'] : NULL, - $data['vek_od'] !== '' ? ((int)$data['vek_od']) : NULL, - $data['vek_do'] !== '' ? ((int)$data['vek_do']) : NULL, - $price, - $data['prihlaska'] == 1, // intentionally == - $data['porada_id'] !== '' ? ((int)$data['porada_id']) : NULL, - $data['porada'] !== '' ? $data['porada'] : NULL, - $data['org'] !== '' ? $data['org'] : NULL, - $data['kontakt'] !== '' ? $data['kontakt'] : NULL, - $data['kontakt_telefon'], - $data['kontakt_email'], - $data['web'] !== '' ? $data['web'] : NULL, - $data['text'] !== '' ? $data['text'] : NULL, - $data['prace'] !== '' ? $data['prace'] : NULL, - $data['sraz'] !== '' ? $data['sraz'] : NULL, - $data['odpovedna'] !== '' ? $data['odpovedna'] : NULL, - $data['pracovni_doba'] !== '' ? ((int)$data['pracovni_doba']) : NULL, - $data['popis_programu'] !== '' ? $data['popis_programu'] : NULL, - $data['ubytovani'] !== '' ? $data['ubytovani'] : NULL, - $data['strava'] !== '' ? $data['strava'] : NULL, - $data['jak_se_prihlasit'] !== '' ? $data['jak_se_prihlasit'] : NULL, - $data['lokalita_mapa'] !== '' ? $data['lokalita_mapa'] : NULL, - $data['priloha_1'] !== '' ? $data['priloha_1'] : NULL, - $data['priloha_2'] !== '' ? $data['priloha_2'] : NULL - ); - } - - - /** - * @return int - */ - public function getId() - { - return $this->id; - } - - /** - * @return string - */ - public function getName() - { - return $this->name; - } - - /** - * @return \DateTimeImmutable - */ - public function getDateFrom() - { - return $this->dateFrom; - } - - /** - * @return \DateTimeImmutable - */ - public function getDateUntil() - { - return $this->dateUntil; - } - - /** - * @return string - */ - public function getType() - { - return $this->type; - } - - /** - * @return Program|NULL - */ - public function getProgram() - { - return $this->program; - } - - /** - * @return Place - */ - public function getPlace() - { - return $this->place; - } - - /** - * @return bool - */ - public function isEnableWebRegistration() - { - return $this->enableWebRegistration; - } - - /** - * @return RegistrationQuestion[]|array - */ - public function getWebRegistrationQuestions() - { - return $this->webRegistrationQuestions; - } - - /** - * @return int|NULL - */ - public function getAgeFrom() - { - return $this->ageFrom; - } - - /** - * @return int|NULL - */ - public function getAgeUntil() - { - return $this->ageUntil; - } - - /** - * @return int|string|NULL - */ - public function getPrice() - { - return $this->price; - } - - /** - * @return Organizer - */ - public function getOrganizer() - { - return $this->organizer; - } - - /** - * @return string|NULL - */ - public function getInvitationText() - { - return $this->invitationText; - } - - /** - * @return string|NULL - */ - public function getWorkDescription() - { - return $this->workDescription; - } - - /** - * @return string|NULL - */ - public function getMeetingInformation() - { - return $this->meetingInformation; - } - - /** - * @return int|NULL - */ - public function getWorkingTime() - { - return $this->workingTime; - } - - /** - * @return string|NULL - */ - public function getProgramDescription() - { - return $this->programDescription; - } - - /** - * @return string|NULL - */ - public function getAccommodation() - { - return $this->accommodation; - } - - /** - * @return string|NULL - */ - public function getFood() - { - return $this->food; - } - - /** - * @return string|NULL - */ - public function getNotes() - { - return $this->notes; - } - - /** - * @return array - */ - public function getAttachments() - { - return $this->attachments; - } - -} diff --git a/src/Response/Event/Event.php b/src/Response/Event/Event.php new file mode 100644 index 0000000..f19ca55 --- /dev/null +++ b/src/Response/Event/Event.php @@ -0,0 +1,519 @@ +id = $id; + $this->name = $name; + $this->dateFrom = $dateFrom; + $this->dateUntil = $dateUntil; + $this->type = $type; + $this->place = Place::from($placeName, $placeAlternativeName, $placeCoordinates); + $this->ageFrom = $ageFrom; + $this->ageUntil = $ageUntil; + $this->price = $price; + $this->timeFrom = $timeFrom; + $this->programDescription = $programDescription; + $this->notes = $notes; + + + // cover photo + + if ($coverPhotoPath !== null) { + $this->coverPhotoPath = $coverPhotoPath; + } + + + // program + + $this->program = Program::from($programSlug, $programName); + + + // registration + + $registrationQuestions = \array_filter([ // exclude all null items + $webRegistrationQuestion1, + $webRegistrationQuestion2, + $webRegistrationQuestion3, + ], function ($v, $k) { + return $v !== null; + }, ARRAY_FILTER_USE_BOTH); + $this->registrationType = RegistrationType::from($registrationType, $registrationQuestions, $contactEmail, $registrationCustomUrl); + + + // organizers + + $this->organizer = Organizer::from( + $organizationalUnitId, + $organizationalUnitName, + $responsiblePerson, + $organizers, + $contactPersonName, + $contactPhone, + $contactEmail + ); + + + // target group + $this->targetGroup = TargetGroup::from($targetGroupId); + + + // invitation + + $this->invitation = Invitation::from( + $invitationIntroduction, + $invitationOrganizationalInformation, + $accommodation, + $food, + $invitationWorkDescription, + $workHoursPerDay, + $invitationPresentationText, + $invitationPresentationPhotos + ); + + + // related website + + if ($relatedWebsite !== null) { + if ( ! self::startsWith($relatedWebsite, 'http')) { // count with no protocol typed URLs + $relatedWebsite = 'http://' . $relatedWebsite; + } + + $this->relatedWebsite = $relatedWebsite; + } + } + + + /** + * @param string[] $data Everything is string as it comes from HTTP response body. + * @return self + * @throws RegistrationTypeException + * @throws BadUsageException + */ + public static function fromResponseData(array $data) + { + $price = 0; + if (isset($data['poplatek']) && $data['poplatek'] !== '') { + $price = $data['poplatek']; + + if (\preg_match('|^[0-9]+$|', $price)) { + $price = (int) $price; + } + } + + // BIS API returns "0", "1", "2" etc. for real options and "" when nothing is set + $food = (isset($data['strava']) && $data['strava'] !== '') ? (int) $data['strava'] : null; + + $invitationPresentationPhotos = []; + if (isset($data['ochutnavka_1']) && $data['ochutnavka_1'] !== '') { + $invitationPresentationPhotos[] = $data['ochutnavka_1']; + } + if (isset($data['ochutnavka_2']) && $data['ochutnavka_2'] !== '') { + $invitationPresentationPhotos[] = $data['ochutnavka_2']; + } + if (isset($data['ochutnavka_3']) && $data['ochutnavka_3'] !== '') { + $invitationPresentationPhotos[] = $data['ochutnavka_3']; + } + if (isset($data['ochutnavka_4']) && $data['ochutnavka_4'] !== '') { + $invitationPresentationPhotos[] = $data['ochutnavka_4']; + } + if (isset($data['ochutnavka_5']) && $data['ochutnavka_5'] !== '') { + $invitationPresentationPhotos[] = $data['ochutnavka_5']; + } + if (isset($data['ochutnavka_6']) && $data['ochutnavka_6'] !== '') { + $invitationPresentationPhotos[] = $data['ochutnavka_6']; + } + + 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'], + (isset($data['program_id']) && $data['program_id'] !== '') ? $data['program_id'] : null, + (isset($data['program']) && $data['program'] !== '') ? $data['program'] : null, + $data['lokalita'], + (isset($data['lokalita_misto']) && $data['lokalita_misto'] !== '') ? $data['lokalita_misto'] : null, + (isset($data['lokalita_gps']) && $data['lokalita_gps'] !== '') ? $data['lokalita_gps'] : null, + (int) $data['prihlaska'], + (isset($data['add_info_title']) && $data['add_info_title'] !== '') ? $data['add_info_title'] : null, + (isset($data['add_info_title_2']) && $data['add_info_title_2'] !== '') ? $data['add_info_title_2'] : null, + (isset($data['add_info_title_3']) && $data['add_info_title_3'] !== '') ? $data['add_info_title_3'] : null, + (isset($data['kontakt_url']) && $data['kontakt_url'] !== '') ? $data['kontakt_url'] : null, + (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, + (isset($data['porada_id']) && $data['porada_id'] !== '') ? ((int)$data['porada_id']) : null, + (isset($data['porada']) && $data['porada'] !== '') ? $data['porada'] : null, + (isset($data['org']) && $data['org'] !== '') ? $data['org'] : null, + (isset($data['kontakt']) && $data['kontakt'] !== '') ? $data['kontakt'] : null, + $data['kontakt_telefon'], + $data['kontakt_email'], + (int) $data['prokoho'], + (isset($data['text_info']) && $data['text_info'] !== '') ? $data['text_info'] : null, + (isset($data['text_uvod']) && $data['text_uvod'] !== '') ? $data['text_uvod'] : null, + (isset($data['text_mnam']) && $data['text_mnam'] !== '') ? $data['text_mnam'] : null, + $invitationPresentationPhotos, + (isset($data['text_dobr']) && $data['text_dobr'] !== '') ? $data['text_dobr'] : null, + (isset($data['sraz']) && $data['sraz'] !== '') ? $data['sraz'] : null, + (isset($data['odpovedna']) && $data['odpovedna'] !== '') ? $data['odpovedna'] : null, + (isset($data['pracovni_doba']) && $data['pracovni_doba'] !== '') ? ((int) $data['pracovni_doba']) : null, + (isset($data['popis_programu']) && $data['popis_programu'] !== '') ? $data['popis_programu'] : null, + (isset($data['ubytovani']) && $data['ubytovani'] !== '') ? $data['ubytovani'] : null, + $food, + (isset($data['jak_se_prihlasit']) && $data['jak_se_prihlasit'] !== '') ? $data['jak_se_prihlasit'] : null, + (isset($data['web']) && $data['web'] !== '') ? $data['web'] : null + ); + } + + + /** + * @return int + */ + public function getId() + { + return $this->id; + } + + /** + * @return string|null + */ + public function getCoverPhotoPath() + { + return $this->coverPhotoPath; + } + + /** + * @return bool + */ + public function hasCoverPhoto() + { + return $this->coverPhotoPath !== null; + } + + /** + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * @return \DateTimeImmutable + */ + public function getDateFrom() + { + return $this->dateFrom; + } + + /** + * @return \DateTimeImmutable + */ + public function getDateUntil() + { + return $this->dateUntil; + } + + /** + * @return string + */ + public function getType() + { + return $this->type; + } + + /** + * @return Program + */ + public function getProgram() + { + return $this->program; + } + + /** + * @return Place + */ + public function getPlace() + { + return $this->place; + } + + /** + * @return RegistrationType + */ + public function getRegistrationType() + { + return $this->registrationType; + } + + /** + * @return int|null + */ + public function getAgeFrom() + { + return $this->ageFrom; + } + + /** + * @return int|null + */ + public function getAgeUntil() + { + return $this->ageUntil; + } + + /** + * @return int|string + */ + public function getPrice() + { + return $this->price; + } + + public function isPaid() + { + return $this->price !== 0; + } + + /** + * @return Organizer + */ + public function getOrganizer() + { + return $this->organizer; + } + + /** + * @return TargetGroup + */ + public function getTargetGroup() + { + return $this->targetGroup; + } + + /** + * @return Invitation|null + */ + public function getInvitation() + { + return $this->invitation; + } + + /** + * @return bool + */ + public function hasTimeFrom() + { + return $this->timeFrom !== null; + } + + /** + * @return string|null + */ + public function getTimeFrom() + { + return $this->timeFrom; + } + + /** + * @return string|null + */ + public function getProgramDescription() + { + return $this->programDescription; + } + + /** + * @return string|null + */ + public function getNotes() + { + return $this->notes; + } + + /** + * @return bool + */ + public function hasRelatedWebsite() + { + return $this->relatedWebsite !== null; + } + + /** + * @return string|null + */ + public function getRelatedWebsite() + { + return $this->relatedWebsite; + } + + + /** + * Extracted from \Nette\Utils\Strings (v2.3) + * Starts the $haystack string with the prefix $needle? + * @param string + * @param string + * @return bool + */ + private static function startsWith($haystack, $needle) + { + return strncmp($haystack, $needle, strlen($needle)) === 0; + } + +} diff --git a/src/Response/Event/Invitation/Food.php b/src/Response/Event/Invitation/Food.php new file mode 100644 index 0000000..2f9cf0a --- /dev/null +++ b/src/Response/Event/Invitation/Food.php @@ -0,0 +1,87 @@ +isListed = true; + + $this->isOfTypeChooseable = $food === self::CHOOSEABLE; + $this->isOfTypeVegetarian = $food === self::VEGETARIAN; + $this->isOfTypeNonVegetarian = $food === self::NON_VEGETARIAN; + } + } + + /** + * @param int|null $food + * @return self + */ + public static function from($food) + { + return new self($food); + } + + + /** + * @return bool + */ + public function isListed() + { + return $this->isListed; + } + + /** + * @return bool + */ + public function isOfTypeChooseable() + { + return $this->isOfTypeChooseable; + } + + /** + * @return bool + */ + public function isOfTypeVegetarian() + { + return $this->isOfTypeVegetarian; + } + + /** + * @return bool + */ + public function isOfTypeNonVegetarian() + { + return $this->isOfTypeNonVegetarian; + } + +} diff --git a/src/Response/Event/Invitation/Invitation.php b/src/Response/Event/Invitation/Invitation.php new file mode 100644 index 0000000..b936b3c --- /dev/null +++ b/src/Response/Event/Invitation/Invitation.php @@ -0,0 +1,185 @@ +introduction = $introduction; + $this->organizationalInformation = $organizationalInformation; + + if ($accommodation !== null) { + $this->accommodation = $accommodation; + } + + $this->food = Food::from($food); + + $this->workDescription = $workDescription; + + if ($workHoursPerDay !== null) { + $this->workHoursPerDay = $workHoursPerDay; + } + + if ($presentationText !== null || \count($presentationPhotos) > 0) { + $this->presentation = Presentation::from($presentationText, $presentationPhotos); + } + } + + /** + * @param string $introduction + * @param string $organizationalInformation + * @param string|null $accommodation + * @param int|null $food + * @param string $workDescription + * @param int|null $workHoursPerDay + * @param string|null $presentationText + * @param string[] $presentationPhotos + * @return self + */ + public static function from( + $introduction, + $organizationalInformation, + $accommodation = null, + $food = null, + $workDescription, + $workHoursPerDay = null, + $presentationText = null, + array $presentationPhotos = [] + ) { + return new self( + $introduction, + $organizationalInformation, + $accommodation, + $food, + $workDescription, + $workHoursPerDay, + $presentationText, + $presentationPhotos + ); + } + + + /** + * @return string + */ + public function getIntroduction() + { + return $this->introduction; + } + + /** + * @return string + */ + public function getOrganizationalInformation() + { + return $this->organizationalInformation; + } + + /** + * @return bool + */ + public function isAccommodationListed() + { + return $this->accommodation !== null; + } + + /** + * @return string|null + */ + public function getAccommodation() + { + return $this->accommodation; + } + + /** + * @return Food + */ + public function getFood() + { + return $this->food; + } + + /** + * @return string + */ + public function getWorkDescription() + { + return $this->workDescription; + } + + /** + * @return bool + */ + public function areWorkHoursPerDayListed() + { + return $this->workHoursPerDay !== null; + } + + /** + * @return int|null + */ + public function getWorkHoursPerDay() + { + return $this->workHoursPerDay; + } + + /** + * @return bool + */ + public function hasPresentation() + { + return $this->presentation !== null; + } + + /** + * @return Presentation|null + */ + public function getPresentation() + { + return $this->presentation; + } + +} diff --git a/src/Response/Event/Invitation/Photo.php b/src/Response/Event/Invitation/Photo.php new file mode 100644 index 0000000..ca9b745 --- /dev/null +++ b/src/Response/Event/Invitation/Photo.php @@ -0,0 +1,40 @@ +path = $path; + } + + + /** + * @param $path + * @return self + */ + public static function from($path) + { + return new self($path); + } + + + /** + * @return string + */ + public function getPath() + { + return $this->path; + } + +} diff --git a/src/Response/Event/Invitation/Presentation.php b/src/Response/Event/Invitation/Presentation.php new file mode 100644 index 0000000..f85a72c --- /dev/null +++ b/src/Response/Event/Invitation/Presentation.php @@ -0,0 +1,103 @@ +text = $text; + } + + if (\count($photoPaths) > 0) { + $this->addPhotos($photoPaths); + } + } + + + /** + * @param string|null $text + * @param string[] $photoPaths + * @return self + */ + public static function from($text = null, array $photoPaths) + { + return new self($text, $photoPaths); + } + + /** + * @param string $photoPath + * @return self + */ + private function addPhoto($photoPath) + { + $this->hasAnyPhotos = true; + $this->photos[] = Photo::from($photoPath); + + return $this; + } + + /** + * @param string[] $photoPaths + * @return self + */ + private function addPhotos(array $photoPaths) + { + foreach ($photoPaths as $photoPath) { + $this->addPhoto($photoPath); + } + + return $this; + } + + + /** + * @return bool + */ + public function hasText() + { + return $this->text !== null; + } + + /** + * @return string|null + */ + public function getText() + { + return $this->text; + } + + /** + * @return bool + */ + public function hasAnyPhotos() + { + return $this->hasAnyPhotos; + } + + /** + * @return Photo[] + */ + public function getPhotos() + { + return $this->photos; + } + +} diff --git a/src/Response/Event/Organizer.php b/src/Response/Event/Organizer.php new file mode 100644 index 0000000..ade2d0a --- /dev/null +++ b/src/Response/Event/Organizer.php @@ -0,0 +1,142 @@ +organizationalUnit = ($organizationalUnitId !== null && $organizationalUnitName !== null) ? OrganizerOrganizationalUnit::from($organizationalUnitId, $organizationalUnitName) : null; + $this->responsiblePerson = $responsiblePerson; + $this->organizers = $organizers; + $this->contactPersonName = $contactPersonName; + $this->contactPhone = $contactPhone; + $this->contactEmail = $contactEmail; + } + + /** + * @param int|null $organizationalUnitId + * @param string|null $organizationalUnitName + * @param string|null $responsiblePerson + * @param string|null $organizers + * @param string|null $contactPersonName + * @param string $contactPhone + * @param string $contactEmail + * + * @return self + */ + public static function from( + $organizationalUnitId = null, + $organizationalUnitName = null, + $responsiblePerson = null, + $organizers = null, + $contactPersonName = null, + $contactPhone, + $contactEmail + ) { + return new self( + $organizationalUnitId, + $organizationalUnitName, + $responsiblePerson, + $organizers, + $contactPersonName, + $contactPhone, + $contactEmail + ); + } + + + /** + * @return OrganizerOrganizationalUnit|null + */ + public function getOrganizationalUnit() + { + return $this->organizationalUnit; + } + + /** + * @return string|null + */ + public function getResponsiblePerson() + { + return $this->responsiblePerson; + } + + /** + * @return bool + */ + public function areOrganizersListed() + { + return $this->organizers !== null; + } + + /** + * @return string|null + */ + public function getOrganizers() + { + return $this->organizers; + } + + /** + * @return string|null + */ + public function getContactPersonName() + { + return $this->contactPersonName; + } + + /** + * @return string + */ + public function getContactPhone() + { + return $this->contactPhone; + } + + /** + * @return string + */ + public function getContactEmail() + { + return $this->contactEmail; + } + +} diff --git a/src/Response/OrganizerOrganizationalUnit.php b/src/Response/Event/OrganizerOrganizationalUnit.php similarity index 63% rename from src/Response/OrganizerOrganizationalUnit.php rename to src/Response/Event/OrganizerOrganizationalUnit.php index ae6a3e2..e36ec14 100644 --- a/src/Response/OrganizerOrganizationalUnit.php +++ b/src/Response/Event/OrganizerOrganizationalUnit.php @@ -1,10 +1,10 @@ id = $id; $this->name = $name; } + /** + * @param int $id + * @param string $name + * @return self + */ + public static function from($id, $name) + { + return new self($id, $name); + } + /** * @return int diff --git a/src/Response/Event/Place.php b/src/Response/Event/Place.php new file mode 100644 index 0000000..efa4682 --- /dev/null +++ b/src/Response/Event/Place.php @@ -0,0 +1,75 @@ +name = $alternativeName !== null ? $alternativeName : $name; // It looks like alternative names are more concrete. + + if ($coordinates !== null && \preg_match('|[0-9]+(\.[0-9]+) [0-9]+(\.[0-9]+)|', $coordinates)) { // Only `49.132456 16.123456` format is used by users right now. + $this->coordinates = $coordinates; + } + } + + /** + * @param string $name + * @param string|null $alternativeName + * @param string|null $coordinates + * @return self + */ + public static function from( + $name, + $alternativeName = null, + $coordinates = null + ) { + return new self($name, $alternativeName, $coordinates); + } + + + /** + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * @return bool + */ + public function areCoordinatesListed() + { + return $this->coordinates !== null; + } + + /** + * @return string|null + */ + public function getCoordinates() + { + return $this->coordinates; + } + +} diff --git a/src/Response/Event/Program.php b/src/Response/Event/Program.php new file mode 100644 index 0000000..91b7c83 --- /dev/null +++ b/src/Response/Event/Program.php @@ -0,0 +1,141 @@ +slug = $slug; + + if ($name !== null) { + $this->name = $name; + } + } + + /** + * @param string|null $slug + * @param string|null $name + * @return self + */ + public static function from($slug = null, $name = null) + { + return new self($slug, $name); + } + + + /** + * @return string + */ + public function getSlug() + { + return $this->slug; + } + + /** + * @return string + */ + public function getName() + { + return $this->name; + } + + + /** + * @return bool + */ + public function isNotSelected() + { + return $this->slug === self::PROGRAM_NONE; + } + + /** + * @return bool + */ + public function isOfTypeNature() + { + return $this->slug === self::PROGRAM_NATURE; + } + + /** + * @return bool + */ + public function isOfTypeSights() + { + return $this->slug === self::PROGRAM_SIGHTS; + } + + /** + * @return bool + */ + public function isOfTypeBrdo() + { + return $this->slug === self::PROGRAM_BRDO; + } + + /** + * @return bool + */ + public function isOfTypeEkostan() + { + return $this->slug === self::PROGRAM_EKOSTAN; + } + + /** + * @return bool + */ + public function isOfTypePsb() + { + return $this->slug === self::PROGRAM_PSB; + } + + /** + * @return bool + */ + public function isOfTypeEducation() + { + return $this->slug === self::PROGRAM_EDUCATION; + } + +} diff --git a/src/Response/Event/Registration/RegistrationQuestion.php b/src/Response/Event/Registration/RegistrationQuestion.php new file mode 100644 index 0000000..4125336 --- /dev/null +++ b/src/Response/Event/Registration/RegistrationQuestion.php @@ -0,0 +1,47 @@ +question = $question; + } + + /** + * @param string $question + * @return self + */ + public static function from($question) + { + return new self($question); + } + + + /** + * @return string + */ + public function toString() + { + return $this->__toString(); + } + + /** + * @return string + */ + public function __toString() + { + return $this->question; + } + +} diff --git a/src/Response/Event/Registration/RegistrationType.php b/src/Response/Event/Registration/RegistrationType.php new file mode 100644 index 0000000..4463dec --- /dev/null +++ b/src/Response/Event/Registration/RegistrationType.php @@ -0,0 +1,199 @@ +type = $type; + + if ($type === self::TYPE_VIA_BRONTOWEB && $questions !== null && \count($questions) > 0) { + $this->questions = \array_map(function ($question) { + return RegistrationQuestion::from($question); + }, $questions); + } + + if ($type === self::TYPE_VIA_EMAIL) { + if ($email === null) { + $this->hasValidData = false; + } + + $this->email = $email; + } + + if ($type === self::TYPE_VIA_CUSTOM_WEBPAGE) { + if ($url === null) { + $this->hasValidData = false; + } + + $this->url = $url; + } + } + + /** + * @param int $type + * @param array|null $questions + * @param string|null $email + * @param string|null $url + * @return self + */ + public static function from($type, array $questions = null, $email = null, $url = null) + { + return new self($type, $questions, $email, $url); + } + + + // registration via Brontoweb + + /** + * @return bool + */ + public function isOfTypeBrontoWeb() + { + return $this->type === self::TYPE_VIA_BRONTOWEB; + } + + /** + * @return bool + */ + public function areAnyQuestions() + { + return \count($this->questions) > 0; + } + + /** + * @return RegistrationQuestion[] + */ + public function getQuestions() + { + return $this->questions; + } + + + // registration via e-mail + + /** + * @return bool + */ + public function isOfTypeEmail() + { + return $this->type === self::TYPE_VIA_EMAIL; + } + + /** + * @return string|null + * @throws RegistrationTypeException + * @throws BadUsageException + */ + public function getEmail() + { + if ( ! $this->hasValidData()) { + throw RegistrationTypeException::missingAdditionalData('email', $this->type); + } + + if ( ! $this->isOfTypeEmail()) { + throw new BadUsageException('This method can not be called when the registration is not of `via e-mail` type.'); + } + + return $this->email; + } + + + // registration via custom webpage + + /** + * @return bool + */ + public function isOfTypeCustomWebpage() + { + return $this->type === self::TYPE_VIA_CUSTOM_WEBPAGE; + } + + /** + * @return string|null + * @throws RegistrationTypeException + * @throws BadUsageException + */ + public function getUrl() + { + if ( ! $this->hasValidData()) { + throw RegistrationTypeException::missingAdditionalData('url', $this->type); + } + + if ( ! $this->isOfTypeCustomWebpage()) { + throw new BadUsageException('This method can not be called when the registration is not of `via custom webpage` type.'); + } + + return $this->url; + } + + + // no registration needed + + /** + * @return bool + */ + public function isOfTypeNone() + { + return $this->type === self::TYPE_NONE; + } + + + // registration disabled + + public function isOfTypeDisabled() + { + return $this->type === self::TYPE_DISABLED; + } + + + public function hasValidData() + { + return $this->hasValidData; + } + +} diff --git a/src/Response/Event/TargetGroup.php b/src/Response/Event/TargetGroup.php new file mode 100644 index 0000000..8cb76a3 --- /dev/null +++ b/src/Response/Event/TargetGroup.php @@ -0,0 +1,90 @@ +id = $id; + } + + /** + * @param int $id + * @return self + */ + public static function from($id) + { + return new self($id); + } + + + /** + * @return bool + */ + public function isOfTypeEveryone() + { + return $this->id === self::EVERYONE; + } + + /** + * @return bool + */ + public function isOfTypeAdults() + { + return $this->id === self::ADULTS; + } + + /** + * @return bool + */ + public function isOfTypeChildren() + { + return $this->id === self::CHILDREN; + } + + /** + * @return bool + */ + public function isOfTypeFamilies() + { + return $this->id === self::FAMILIES; + } + + /** + * @return bool + */ + public function isOfTypeFirstTimeAttendees() + { + return $this->id === self::FIRST_TIME_ATTENDEES; + } + +} diff --git a/src/Response/OrganizationalUnit.php b/src/Response/OrganizationalUnit/OrganizationalUnit.php similarity index 69% rename from src/Response/OrganizationalUnit.php rename to src/Response/OrganizationalUnit/OrganizationalUnit.php index 04f1fdf..cb0e428 100644 --- a/src/Response/OrganizationalUnit.php +++ b/src/Response/OrganizationalUnit/OrganizationalUnit.php @@ -1,8 +1,6 @@ id = $id; $this->name = $name; @@ -90,8 +88,8 @@ public function __construct( self::TYPE_BASE, self::TYPE_REGIONAL, self::TYPE_OFFICE, - ], TRUE)) { - throw new InvalidArgumentException('Type `' . $type . '` is not of valid types.'); + ], true)) { + throw new UnknownOrganizationUnitTypeException('Type `' . $type . '` is not of valid types.'); } $this->type = $type; } @@ -105,12 +103,12 @@ public static function fromResponseData(array $data) $data['ulice'], $data['mesto'], $data['psc'], - $data['telefon'] !== '' ? $data['telefon'] : NULL, - $data['email'] !== '' ? $data['email'] : NULL, - $data['www'] !== '' ? $data['www'] : NULL, + (isset($data['telefon']) && $data['telefon'] !== '') ? $data['telefon'] : null, + (isset($data['email']) && $data['email'] !== '') ? $data['email'] : null, + (isset($data['www']) && $data['www'] !== '') ? $data['www'] : null, (int) $data['uroven'], - $data['predseda'] !== '' ? $data['predseda'] : NULL, - $data['hospodar'] !== '' ? $data['hospodar'] : NULL + (isset($data['predseda']) && $data['predseda'] !== '') ? $data['predseda'] : null, + (isset($data['hospodar']) && $data['hospodar'] !== '') ? $data['hospodar'] : null ); } @@ -156,7 +154,7 @@ public function getPostCode() } /** - * @return string|NULL + * @return string|null */ public function getPhone() { @@ -164,7 +162,7 @@ public function getPhone() } /** - * @return string|NULL + * @return string|null */ public function getEmail() { @@ -172,7 +170,7 @@ public function getEmail() } /** - * @return string|NULL + * @return string|null */ public function getWebsite() { @@ -188,7 +186,7 @@ public function getType() } /** - * @return string|NULL + * @return string|null */ public function getChairman() { @@ -196,7 +194,7 @@ public function getChairman() } /** - * @return string|NULL + * @return string|null */ public function getManager() { diff --git a/src/Response/OrganizationalUnit/exceptions.php b/src/Response/OrganizationalUnit/exceptions.php new file mode 100644 index 0000000..ba73fa9 --- /dev/null +++ b/src/Response/OrganizationalUnit/exceptions.php @@ -0,0 +1,7 @@ +organizationalUnit = $organizationalUnit; - $this->responsiblePerson = $responsiblePerson; - $this->organizers = $organizers; - $this->contactPersonName = $contactPersonName; - $this->contactPhone = $contactPhone; - $this->contactEmail = $contactEmail; - $this->contactWebsite = $contactWebsite; - } - - - /** - * @return OrganizerOrganizationalUnit|NULL - */ - public function getOrganizationalUnit() - { - return $this->organizationalUnit; - } - - /** - * @return string|NULL - */ - public function getResponsiblePerson() - { - return $this->responsiblePerson; - } - - /** - * @return string|NULL - */ - public function getOrganizers() - { - return $this->organizers; - } - - /** - * @return string|NULL - */ - public function getContactPersonName() - { - return $this->contactPersonName; - } - - /** - * @return string - */ - public function getContactPhone() - { - return $this->contactPhone; - } - - /** - * @return string - */ - public function getContactEmail() - { - return $this->contactEmail; - } - - /** - * @return string|NULL - */ - public function getContactWebsite() - { - return $this->contactWebsite; - } - -} diff --git a/src/Response/Place.php b/src/Response/Place.php deleted file mode 100644 index 7b6dc1c..0000000 --- a/src/Response/Place.php +++ /dev/null @@ -1,73 +0,0 @@ -id = $id; - $this->name = $name; - - if (\strncmp($mapLinkOrCoords, 'http', \strlen('http')) === 0) { // Copied from `Nette\Utils\Strings::startsWith()`. - $this->mapLink = $mapLinkOrCoords; - } - elseif (\preg_match('|[0-9]+(\.[0-9]+)N, [0-9]+(\.[0-9]+)E|', $mapLinkOrCoords)) { // Only `49.132456N, 16.123456E` format is used by users right now. - $this->coords = $mapLinkOrCoords; - } - } - - - /** - * @return int|NULL - */ - public function getId() - { - return $this->id; - } - - /** - * @return string - */ - public function getName() - { - return $this->name; - } - - /** - * @return string|NULL - */ - public function getMapLink() - { - return $this->mapLink; - } - - /** - * @return string|NULL - */ - public function getCoords() - { - return $this->coords; - } - -} diff --git a/src/Response/Program.php b/src/Response/Program.php deleted file mode 100644 index c3f13e5..0000000 --- a/src/Response/Program.php +++ /dev/null @@ -1,81 +0,0 @@ -slug = $slug; - $this->name = $name; - } - - - /** - * @return string - */ - public function getSlug() - { - return $this->slug; - } - - /** - * @return string - */ - public function getName() - { - return $this->name; - } - - - /** - * @return bool - */ - public function isOfTypeNature() - { - return $this->slug === self::PROGRAM_NATURE; - } - - /** - * @return bool - */ - public function isOfTypeSights() - { - return $this->slug === self::PROGRAM_SIGHTS; - } - -} diff --git a/src/Response/RegistrationQuestion.php b/src/Response/RegistrationQuestion.php deleted file mode 100644 index eb2e3d9..0000000 --- a/src/Response/RegistrationQuestion.php +++ /dev/null @@ -1,30 +0,0 @@ -question = $question; - } - - - /** - * @return string - */ - public function getQuestion() - { - return $this->question; - } - -} diff --git a/src/Response/Response.php b/src/Response/Response.php index ae5df08..9a2166e 100644 --- a/src/Response/Response.php +++ b/src/Response/Response.php @@ -10,6 +10,7 @@ final class Response const TAG_RESULT = 'result'; const TAG_RESULT_ATTRIBUTE_ERROR = 'error'; + const TAG_ATTRIBUTE_ID = 'id'; /** @var ResponseInterface */ @@ -37,13 +38,18 @@ private function parseDom(\DOMDocument $domDocument) $rowNodeList = $domFinder->query('*', $domDocument->getElementsByTagName(self::TAG_RESULT)->item(0)); foreach ($rowNodeList as $rowNode) { - \assert($rowNode instanceof \DOMNode); + \assert($rowNode instanceof \DOMElement); + /** @var array $row */ $row = []; foreach ($domFinder->query('*', $rowNode) as $node) { - \assert($node instanceof \DOMNode); + \assert($node instanceof \DOMElement); - $row[$node->nodeName] = $node->nodeValue; + // 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; diff --git a/src/Response/exceptions.php b/src/Response/exceptions.php new file mode 100644 index 0000000..57904d0 --- /dev/null +++ b/src/Response/exceptions.php @@ -0,0 +1,70 @@ +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 7ed4155..b3f1665 100644 --- a/src/exceptions.php +++ b/src/exceptions.php @@ -3,11 +3,31 @@ namespace HnutiBrontosaurus\BisApiClient; -class InvalidArgumentException extends \InvalidArgumentException +// overall exceptions + +abstract class BisApiClientLogicException extends \LogicException +{} + +abstract class BisApiClientRuntimeException extends \RuntimeException +{} + + +// working with API exceptions + +final class InvalidArgumentException extends BisApiClientLogicException +{} + +final class BadUsageException extends BisApiClientLogicException +{} + + +// communicating with BIS exceptions + +abstract class ConnectionException extends BisApiClientRuntimeException {} -class ResourceNotFoundException extends \RuntimeException +final class TransferErrorException extends ConnectionException {} -class BisClientException extends \RuntimeException +final class NotFoundException extends ConnectionException {}