Passed
Push — master ( 4d256e...7fd2cf )
by Daniel
02:25
created

NovaSearchPartnerMethod::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 3
c 1
b 0
f 0
nc 1
nop 3
dl 0
loc 8
ccs 4
cts 4
cp 1
crap 1
rs 10
1
<?php
2
3
namespace OrcaServices\NovaApi\Method;
4
5
use Cake\Chronos\Chronos;
6
use DOMDocument;
7
use DOMElement;
8
use Exception;
9
use OrcaServices\NovaApi\Parameter\NovaSearchPartnerParameter;
10
use OrcaServices\NovaApi\Parser\NovaApiErrorParser;
11
use OrcaServices\NovaApi\Parser\NovaMessageParser;
12
use OrcaServices\NovaApi\Result\NovaPartner;
13
use OrcaServices\NovaApi\Result\NovaSearchPartnerResult;
14
use OrcaServices\NovaApi\Soap\NovaApiSoapAction;
15
use OrcaServices\NovaApi\Soap\NovaParameterMap;
16
use OrcaServices\NovaApi\Soap\NovaParameterWriter;
17
use OrcaServices\NovaApi\Type\GenderType;
18
use OrcaServices\NovaApi\Xml\XmlDocument;
19
20
/**
21
 * SOAP method.
22
 */
23
final class NovaSearchPartnerMethod implements NovaMethod
24
{
25
    /**
26
     * @var NovaApiSoapAction
27
     */
28
    private $novaSoapAction;
29
30
    /**
31
     * @var NovaApiErrorParser
32
     */
33
    private $novaErrorParser;
34
35
    /**
36
     * @var NovaMessageParser
37
     */
38
    private $novaMessageParser;
39
40
    /**
41
     * NovaSearchPartnerMethod constructor.
42
     *
43
     * @param NovaApiSoapAction $novaSoapAction The novaSoapAction
44
     * @param NovaApiErrorParser $novaErrorParser The novaErrorParser
45
     * @param NovaMessageParser $novaMessageParser The message parser
46
     */
47 11
    public function __construct(
48
        NovaApiSoapAction $novaSoapAction,
49
        NovaApiErrorParser $novaErrorParser,
50
        NovaMessageParser $novaMessageParser
51
    ) {
52 11
        $this->novaSoapAction = $novaSoapAction;
53 11
        $this->novaErrorParser = $novaErrorParser;
54 11
        $this->novaMessageParser = $novaMessageParser;
55 11
    }
56
57
    /**
58
     * Search a NOVA partner (customer).
59
     *
60
     * https://confluence-ext.sbb.ch/display/NOVAUG/suchePartner
61
     *
62
     * @param NovaSearchPartnerParameter $parameter The parameters
63
     *
64
     * @throws Exception
65
     *
66
     * @return NovaSearchPartnerResult The partners matching the search parameter
67
     */
68 3
    public function searchPartner(NovaSearchPartnerParameter $parameter): NovaSearchPartnerResult
69
    {
70
        // The SOAP endpoint url
71
        // https://echo-api.3scale.net/novagp/geschaeftspartner/public/MAJOR.MINOR/GeschaeftspartnerService
72 3
        $url = $this->novaSoapAction->getNovaBusinessPartnerServiceUrl();
73
74
        // The SOAP action (http header)
75 3
        $soapAction = $this->novaSoapAction->getSoapAction('geschaeftspartner', 'suchePartner');
76
77
        // The SOAP content (http body)
78 3
        $body = $this->createRequestBody($parameter);
79
80
        try {
81 3
            $xmlContent = $this->novaSoapAction->invokeSoapRequest($url, $soapAction, $body);
82 3
            $xml = XmlDocument::createFromXmlString($xmlContent);
83
84 3
            return $this->createResult($xml);
85
        } catch (Exception $exception) {
86
            throw $this->novaErrorParser->createGeneralException($exception);
87
        }
88
    }
89
90
    /**
91
     * Create SOAP body XML content.
92
     *
93
     * @param NovaSearchPartnerParameter $parameter The parameters
94
     *
95
     * @return string The xml content
96
     */
97 3
    private function createRequestBody(NovaSearchPartnerParameter $parameter): string
98
    {
99 3
        $dom = new DOMDocument('1.0', 'utf-8');
100 3
        $dom->formatOutput = true;
101
102 3
        $dom->appendChild($dom->createComment(' powered by Barakuda '));
103
104 3
        $envelope = $dom->createElement('soapenv:Envelope');
105 3
        $dom->appendChild($envelope);
106 3
        $envelope->setAttribute('xmlns:soapenv', 'http://schemas.xmlsoap.org/soap/envelope/');
107
108 3
        $soapHeader = $dom->createElement('soapenv:Header');
109 3
        $envelope->appendChild($soapHeader);
110
111 3
        $body = $dom->createElement('soapenv:Body');
112 3
        $envelope->appendChild($body);
113
114 3
        $method = $dom->createElement('novagp:suchePartner');
115 3
        $body->appendChild($method);
116
117 3
        $this->novaSoapAction->appendMethodNamespaces($method);
118 3
        $this->novaSoapAction->appendDomClientIdentifier($dom, $method, $parameter, 'novagp:');
119 3
        $this->novaSoapAction->appendDomCorrelationContext($dom, $method, $parameter, 'novagp:');
120
121 3
        $partnerSearchParameter = $dom->createElement('novagp:partnerSuchParameter');
122 3
        $method->appendChild($partnerSearchParameter);
123
124 3
        $parameterWriter = new NovaParameterWriter($dom, $partnerSearchParameter);
125
126 3
        $parameterWriter->appendToDocument(
127 3
            new NovaParameterMap(
128
                [
129 3
                    'tkid' => $parameter->tkId,
130 3
                    'grundkartenNummer' => $parameter->cardNumber,
131 3
                    'ckm' => $parameter->ckm,
132 3
                    'name' => $parameter->lastName,
133 3
                    'vorname' => $parameter->firstName,
134 3
                    'mail' => $parameter->mail,
135 3
                    'land' => $parameter->country,
136 3
                    'ort' => $parameter->city,
137 3
                    'plz' => $parameter->postalCode,
138 3
                    'strasseHnr' => $parameter->street,
139 3
                    'geburtsDatum' => $parameter->dateOfBirth ? $parameter->dateOfBirth->format('Y-m-d') : null,
140
                ]
141
            )
142
        );
143
144 3
        $pagingElement = $dom->createElement('novagp:pagingParameter');
145 3
        $partnerSearchParameter->appendChild($pagingElement);
146
147 3
        return (string)$dom->saveXML();
148
    }
149
150
    /**
151
     * Create result object.
152
     *
153
     * @param XmlDocument $xml The xml document
154
     *
155
     * @return NovaSearchPartnerResult The mapped result
156
     */
157 3
    private function createResult(XmlDocument $xml): NovaSearchPartnerResult
158
    {
159 3
        $result = new NovaSearchPartnerResult();
160
161 3
        $xml = $xml->withoutNamespaces();
162
163
        // Find and append all messages
164 3
        foreach ($this->novaMessageParser->findNovaMessages($xml) as $message) {
165
            $result->addMessage($message);
166
        }
167
168
        // Root node
169 3
        $responseNode = $xml->queryFirstNode('/Envelope/Body/suchePartnerResponse');
170 3
        $partnerNodes = $xml->queryNodes('partner', $responseNode);
171
172
        /** @var DOMElement $partnerNode */
173 3
        foreach ($partnerNodes as $partnerNode) {
174 3
            $result->partners[] = $this->createPartner($partnerNode, $xml);
175
        }
176
177 3
        return $result;
178
    }
179
180
    /**
181
     * Map partner node to NovaPartner object.
182
     *
183
     * @param DOMElement $partnerNode The partnerNode
184
     * @param XmlDocument $xml The xml document
185
     *
186
     * @return NovaPartner The new NovaPartner instance
187
     */
188 3
    private function createPartner(DOMElement $partnerNode, XmlDocument $xml): NovaPartner
189
    {
190 3
        $partner = new NovaPartner();
191
192 3
        $partner->tkId = $xml->getAttributeValue('@tkid', $partnerNode);
193 3
        $partner->ckm = $xml->findAttributeValue('@ckm', $partnerNode);
194 3
        $partner->cardNumber = $xml->findAttributeValue('@grundkartenNummer', $partnerNode);
195
196 3
        $changeDate = $xml->findAttributeValue('@mutDatum', $partnerNode);
197 3
        if ($changeDate !== null) {
198 3
            $partner->changedAt = $xml->createChronosFromXsDateTime($changeDate);
199
        }
200
201 3
        $partner->lastName = $xml->findAttributeValue('name/@name', $partnerNode);
202 3
        $partner->firstName = $xml->findAttributeValue('name/@vorname', $partnerNode);
203 3
        $partner->title = $xml->findAttributeValue('@titel', $partnerNode);
204
205 3
        $deceased = $xml->findAttributeValue('@verstorben', $partnerNode);
206 3
        if ($deceased !== null) {
207 3
            $partner->deceased = $deceased === 'false' ? 0 : 1;
208
        }
209
210
        // Date of birth can be empty sometimes
211 3
        $dateOfBirth = $xml->findAttributeValue('@geburtsDatum', $partnerNode);
212 3
        if ($dateOfBirth) {
213 3
            $dateOfBirth = Chronos::createFromFormat('Y-m-d', $dateOfBirth)->setTime(0, 0);
214 3
            $partner->dateOfBirth = $dateOfBirth;
0 ignored issues
show
Documentation Bug introduced by
It seems like $dateOfBirth can also be of type false. However, the property $dateOfBirth is declared as type Cake\Chronos\Chronos|null. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
215
        }
216
217 3
        $gender = $xml->findAttributeValue('@geschlecht', $partnerNode);
218 3
        $genderTypeId = $gender === 'MAENNLICH' ? GenderType::MEN : GenderType::WOMEN;
219 3
        $partner->genderTypeId = $genderTypeId;
220
221
        // Address
222 3
        $addressNodes = $xml->queryNodes('sitz/adresse', $partnerNode);
223
224
        // Could be empty, one, or more then one address: postal addresse, communication address etc.
225 3
        if ($addressNodes->length >= 1) {
226 3
            $addressNode = $xml->getFirstNode($addressNodes);
227
228 3
            $country = $xml->findAttributeValue('@land', $addressNode);
229 3
            $partner->country = $country;
230
231 3
            $city = $xml->findAttributeValue('@ort', $addressNode);
232 3
            $partner->city = $city;
233
234 3
            $postalCode = $xml->findAttributeValue('@plz', $addressNode);
235 3
            $partner->postalCode = $postalCode;
236
237 3
            $additional = $xml->findAttributeValue('@adressZusatz', $addressNode);
238 3
            if ($additional !== null) {
239
                $partner->additional = $additional;
240
            }
241
242 3
            $street = $xml->findAttributeValue('@strasseHnr', $addressNode);
243 3
            $partner->street = $street;
244
245 3
            $poBox = $xml->findAttributeValue('@postfach', $addressNode);
246 3
            if ($poBox !== null) {
247 3
                $partner->poBox = $poBox;
248
            }
249
        }
250
251
        // MOBIL, FESTNETZ or MAIL
252 3
        $phoneNumber = $xml->findAttributeValue('festnetz/@formatiertE123', $partnerNode);
253 3
        if ($phoneNumber !== null) {
254 3
            $partner->phoneNumber = str_replace(' ', '', $phoneNumber);
255
        }
256
257 3
        $mobileNumber = $xml->findAttributeValue('mobil/@formatiertE123', $partnerNode);
258 3
        if ($mobileNumber !== null) {
259 3
            $partner->mobileNumber = str_replace(' ', '', $mobileNumber);
260
        }
261
262 3
        $email = $xml->findAttributeValue('@email', $partnerNode);
263 3
        if ($email && filter_var($email, FILTER_VALIDATE_EMAIL) !== false) {
264 3
            $partner->email = $email;
265
        }
266
267 3
        return $partner;
268
    }
269
}
270