Files
myep-team/src/BusProNet/ResponseParser.php
T

321 lines
11 KiB
PHP

<?php
namespace App\BusProNet;
use App\BusProNet\Model\Address;
use App\BusProNet\Model\BaseDataResponse;
use App\BusProNet\Model\Communication;
use App\BusProNet\Model\Country;
use App\BusProNet\Model\CrmAttribute;
use App\BusProNet\Model\CrmAttributeGroup;
use App\BusProNet\Model\CrmAttributesResponse;
use App\BusProNet\Model\Hotel;
use App\BusProNet\Model\NotificationResponse;
use App\BusProNet\Model\Pickup;
use App\BusProNet\Model\ProfileResponse;
use App\BusProNet\Model\ProfileUpdateResponse;
use Symfony\Component\OptionsResolver\OptionsResolver;
class ResponseParser
{
private array $config;
public function __construct(array $options)
{
$this->config = $this->resolveOptions($options);
}
/**
* @throws ResponseParserException
*/
public function parseXmlString(string $type, string $content): mixed
{
$xml = simplexml_load_string($content);
if (false === $xml) {
throw new ResponseParserException('Unable to parse XML response');
}
// Override type when present in XML to catch error responses
$responseType = $type;
$responseTypeXml = $xml->xpath('satz/@typ') ?: [];
if (0 < count($responseTypeXml)) {
$responseType = (string) $responseTypeXml[0];
}
switch ($responseType) {
case ApiClient::TYPE_NOTIFICATION:
return $this->createNotificationResponse($xml);
case ApiClient::TYPE_CUSTOMER_DATA:
$subType = (string) $xml->art;
switch ($subType) {
case 'Adressdaten':
return $this->createProfileResponse($xml);
case 'Adressdaten_Ändern':
return $this->createProfileUpdateResponse($xml);
case 'SelektionCRM':
case 'SelektionCRM_Ändern':
return $this->createCrmAttributesResponse($xml);
}
break;
case ApiClient::TYPE_BASE_DATA_COUNTRIES:
return $this->createCountriesResponse($xml);
case ApiClient::TYPE_BASE_DATA_PICKUPS:
return $this->createPickupsResponse($xml);
case ApiClient::TYPE_BASE_DATA_HOTELS:
return $this->createHotelsResponse($xml);
}
throw new ResponseParserException('Unable to parse XML response');
}
public function createNotificationResponse(\SimpleXMLElement $xml): NotificationResponse
{
$recordXml = $xml->satz;
$code = (int) $recordXml->nr;
$message = (string) $recordXml->text;
return new NotificationResponse($code, $message);
}
public function createProfileResponse(\SimpleXMLElement $xml): ProfileResponse
{
$addressId = (int) $xml->idadresse;
$personId = (int) $xml->idperson;
$addressXml = $xml->adressdaten;
$lastName = (string) $addressXml->name;
$firstName = (string) $addressXml->vorname;
$salutation = (string) $addressXml->anrede;
$title = (string) $addressXml->titel;
$gender = (string) $addressXml->geschlecht;
$gender = 'W' === strtoupper($gender) ? 'F' : strtoupper($gender);
$dateString = (string) $addressXml->geburtsdatum;
$dateOfBirth = null;
if ('' !== $dateString) {
$parsedDate = \DateTimeImmutable::createFromFormat('d.m.Y', $dateString);
$dateOfBirth = false === $parsedDate ? null : $parsedDate;
}
$response = new ProfileResponse();
$response
->setAddressId($addressId)
->setPersonId($personId)
->setFirstName($firstName)
->setName($lastName)
->setTitle($title)
->setSalutation($salutation)
->setGender($gender)
->setDateOfBirth($dateOfBirth)
;
$postalXml = $addressXml->anschrift;
$postalAddressStreet = (string) $postalXml->strasse;
$postalAddressPostcode = (string) $postalXml->plz;
$postalAddressCity = (string) $postalXml->ort;
$postalAddressCountry = (string) $postalXml->land;
$address = new Address();
$address
->setStreet($postalAddressStreet)
->setPostCode($postalAddressPostcode)
->setCity($postalAddressCity)
->setCountry($postalAddressCountry)
;
$response->setAddress($address);
$contactXml = $addressXml->kommunikation;
$phone = (string) $contactXml->telefonprivat;
$mobile = (string) $contactXml->telefonmobil;
$email = (string) $contactXml->email;
$communication = new Communication();
$communication
->setPhone($phone)
->setMobile($mobile)
->setEmail($email)
;
$response->setCommunication($communication);
return $response;
}
public function createProfileUpdateResponse(\SimpleXMLElement $xml): ProfileUpdateResponse
{
$addressId = (int) $xml->idadresse;
$personId = (int) $xml->idperson;
$updated = false;
$updatedXml = $xml->xpath('änderung|aenderung') ?: [];
if (0 < count($updatedXml)) {
$updated = 'true' === strtolower((string) $updatedXml[0]);
}
$response = new ProfileUpdateResponse();
$response
->setAddressId($addressId)
->setPersonId($personId)
->setUpdated($updated)
;
return $response;
}
public function createCrmAttributesResponse(\SimpleXMLElement $xml): CrmAttributesResponse
{
$groups = [];
$isAdmin = $isManager = $isHouseManager = $isTeamer = false;
$hotelCodes = [];
foreach ($xml->selektionsmerkmale->selektionsgruppe as $item) {
$group = new CrmAttributeGroup();
$group->setLabel($item->attributes()['bezeichnung']);
$attributes = [];
foreach ($item->selektion as $subItem) {
$subItemAttributes = $subItem->attributes();
$attributeId = (int) $subItemAttributes['id'];
$attributeLabel = (string) $subItemAttributes['bezeichnung'];
$attributeSelected = 'True' === (string) $subItemAttributes['auswahl'];
$attribute = new CrmAttribute();
$attribute
->setId($attributeId)
->setLabel($attributeLabel)
->setSelected($attributeSelected)
;
$attributes[] = $attribute;
// Matched by id, like every other role: the "Hausleitung XXX" label is BusPro
// wording and must not decide who gets access to which house.
$houseManagerCode = $this->config['bpn_crm_house_manager_ids'][$attribute->getId()] ?? null;
if (null !== $houseManagerCode && true === $attribute->isSelected()) {
$isHouseManager = true;
$hotelCodes[] = $houseManagerCode;
}
if ($this->config['bpn_crm_id_admin'] === $attribute->getId() && true === $attribute->isSelected()) {
$isAdmin = true;
}
if ($this->config['bpn_crm_id_manager'] === $attribute->getId() && true === $attribute->isSelected()) {
$isManager = true;
}
if ($this->config['bpn_crm_id_teamer'] === $attribute->getId() && true === $attribute->isSelected()) {
$isTeamer = true;
}
}
$group->setAttributes($attributes);
$groups[] = $group;
}
// Apply additional role and hotel code for testing purposes when provided
if ($isAdmin && null !== $this->config['bpn_default_hotel_code']) {
$isHouseManager = true;
$hotelCodes[] = $this->config['bpn_default_hotel_code'];
}
$response = new CrmAttributesResponse();
$response
->setAttributeGroups($groups)
->setAdmin($isAdmin)
->setManager($isManager)
->setTeamer($isTeamer)
->setHouseManager($isHouseManager)
->setHotelCodes($hotelCodes)
;
return $response;
}
public function createCountriesResponse(\SimpleXMLElement $xml): BaseDataResponse
{
$countries = [];
foreach ($xml->laender->land as $item) {
$itemAttributes = $item->attributes();
$token = (string) $itemAttributes['kuerzel'];
$country = new Country();
$country
->setId((int) $itemAttributes['id'])
->setName((string) $itemAttributes['bezeichnung'])
->setToken((string) $itemAttributes['kuerzel'])
->setNationality((string) $itemAttributes['nationalitaet'])
;
$countries[$token] = $country;
}
return new BaseDataResponse($countries);
}
public function createPickupsResponse(\SimpleXMLElement $xml): BaseDataResponse
{
$pickups = [];
foreach ($xml->zustieg as $item) {
$itemAttributes = $item->attributes();
$id = (int) $itemAttributes['id'];
$busProId = (int) $itemAttributes['idbuspro'];
$pickup = new Pickup();
$pickup
->setId($id)
->setBusProId($busProId)
->setCode((string) $itemAttributes['code'])
->setCity((string) $item->ort)
->setStreet((string) $item->strasse)
;
$pickups[$busProId] = $pickup;
}
return new BaseDataResponse($pickups);
}
public function createHotelsResponse(\SimpleXMLElement $xml): BaseDataResponse
{
$hotels = [];
foreach ($xml->hotel as $item) {
$itemAttributes = $item->attributes();
$id = (int) $itemAttributes['id'];
$busProId = (int) $itemAttributes['idbuspro'];
$hotel = new Hotel();
$hotel
->setId($id)
->setBusProId($busProId)
->setCode((string) $itemAttributes['code'])
->setName((string) $item->name)
->setCountry(strtolower((string) $item->land))
->setCity((string) $item->ort)
->setStreet((string) $item->strasse)
->setPhone((string) $item->telefon)
->setType((string) $item->art)
->setCostUnit($item->kostenstelle)
;
$hotels[$busProId] = $hotel;
}
return new BaseDataResponse($hotels);
}
private function resolveOptions(array $options): array
{
$optionsResolver = new OptionsResolver();
$optionsResolver->setRequired(['bpn_crm_id_admin', 'bpn_crm_id_manager', 'bpn_crm_id_teamer', 'bpn_crm_house_manager_ids']);
$optionsResolver->setDefaults([
'bpn_default_hotel_code' => null,
]);
$optionsResolver->setAllowedTypes('bpn_crm_id_admin', 'int');
$optionsResolver->setAllowedTypes('bpn_crm_id_manager', 'int');
$optionsResolver->setAllowedTypes('bpn_crm_id_teamer', 'int');
$optionsResolver->setAllowedTypes('bpn_crm_house_manager_ids', 'array');
$optionsResolver->setAllowedTypes('bpn_default_hotel_code', ['string', 'null']);
return $optionsResolver->resolve($options);
}
}