NovaCreateOffersMethod::createRequestBody()   B
last analyzed

Complexity

Conditions 7
Paths 21

Size

Total Lines 97
Code Lines 59

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 46
CRAP Score 7.5238

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 7
eloc 59
c 1
b 0
f 0
nc 21
nop 1
dl 0
loc 97
ccs 46
cts 59
cp 0.7796
crap 7.5238
rs 7.9612

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace OrcaServices\NovaApi\Method;
4
5
use Cake\Chronos\Chronos;
6
use DomainException;
7
use DOMDocument;
8
use DOMElement;
9
use Exception;
10
use InvalidArgumentException;
11
use OrcaServices\NovaApi\Parameter\NovaCreateOffersParameter;
12
use OrcaServices\NovaApi\Parser\NovaApiErrorParser;
13
use OrcaServices\NovaApi\Parser\NovaMessageParser;
14
use OrcaServices\NovaApi\Result\NovaCreateOffersResult;
15
use OrcaServices\NovaApi\Result\NovaOffer;
16
use OrcaServices\NovaApi\Soap\NovaApiSoapAction;
17
use OrcaServices\NovaApi\Type\GenderType;
18
use OrcaServices\NovaApi\Xml\XmlDocument;
19
20
/**
21
 * SOAP method.
22
 */
23
final class NovaCreateOffersMethod 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 13
    public function __construct(
48
        NovaApiSoapAction $novaSoapAction,
49
        NovaApiErrorParser $novaErrorParser,
50
        NovaMessageParser $novaMessageParser
51
    ) {
52 13
        $this->novaSoapAction = $novaSoapAction;
53 13
        $this->novaErrorParser = $novaErrorParser;
54 13
        $this->novaMessageParser = $novaMessageParser;
55 13
    }
56
57
    /**
58
     * Create offers.
59
     *
60
     * https://confluence-ext.sbb.ch/display/NOVAUG/erstelleAngebote
61
     *
62
     * @param NovaCreateOffersParameter $parameter The parameter
63
     *
64
     * @throws Exception If an error occurs
65
     *
66
     * @return NovaCreateOffersResult List of offers
67
     */
68 2
    public function createOffers(NovaCreateOffersParameter $parameter): NovaCreateOffersResult
69
    {
70
        // The SOAP endpoint url
71 2
        $url = $this->novaSoapAction->getNovaSalesServiceUrl();
72
73
        // The SOAP action (http header)
74 2
        $soapAction = $this->novaSoapAction->getSoapAction('vertrieb', 'erstelleAngebote');
75
76
        // The SOAP content (http body)
77 2
        $body = $this->createRequestBody($parameter);
78
79
        try {
80 2
            $xmlContent = $this->novaSoapAction->invokeSoapRequest($url, $soapAction, $body);
81 2
            $xml = XmlDocument::createFromXmlString($xmlContent);
82
83 2
            return $this->createResult($xml);
84
        } catch (Exception $exception) {
85
            throw $this->novaErrorParser->createGeneralException($exception);
86
        }
87
    }
88
89
    /**
90
     * Create SOAP body XML content.
91
     *
92
     * @param NovaCreateOffersParameter $parameter The parameters
93
     *
94
     * @throws InvalidArgumentException
95
     *
96
     * @return string The xml content
97
     */
98 2
    private function createRequestBody(NovaCreateOffersParameter $parameter): string
99
    {
100 2
        $dom = new DOMDocument('1.0', 'utf-8');
101 2
        $dom->formatOutput = true;
102
103 2
        $dom->appendChild($dom->createComment(' powered by Barakuda '));
104
105 2
        $envelope = $dom->createElement('soapenv:Envelope');
106 2
        $dom->appendChild($envelope);
107 2
        $envelope->setAttribute('xmlns:soapenv', 'http://schemas.xmlsoap.org/soap/envelope/');
108
109 2
        $soapHeader = $dom->createElement('soapenv:Header');
110 2
        $envelope->appendChild($soapHeader);
111
112 2
        $body = $dom->createElement('soapenv:Body');
113 2
        $envelope->appendChild($body);
114
115 2
        $method = $dom->createElement('ns18:erstelleAngebote');
116 2
        $body->appendChild($method);
117
118 2
        $this->novaSoapAction->appendMethodNamespaces($method);
119
120 2
        $methodRequest = $dom->createElement('ns18:angebotsRequest');
121 2
        $method->appendChild($methodRequest);
122
123 2
        $methodRequest->setAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance');
124 2
        $methodRequest->setAttribute('xsi:type', 'ns18:ZonenplanBasierterAngebotsRequest');
125
126
        // Ticket valid from
127 2
        $methodRequest->setAttribute('ns18:gueltigAbDatum', $parameter->validFrom->format('Y-m-d'));
128
129 2
        $methodRequest->setAttribute('ns18:kundenSegmenteGruppieren', 'false');
130 2
        $methodRequest->setAttribute('ns18:fachlogLevel', 'OFF');
131
132 2
        $this->novaSoapAction->appendDomClientIdentifier($dom, $methodRequest, $parameter, 'ns18:');
133 2
        $this->novaSoapAction->appendDomCorrelationContext($dom, $methodRequest, $parameter, 'ns18:');
134
135 2
        $methodRequest->appendChild($dom->createElement('ns18:traegerMedium', 'SWISSPASS'));
136
137 2
        $traveller = $dom->createElement('ns18:reisender');
138 2
        $methodRequest->appendChild($traveller);
139
140 2
        $traveller->setAttribute('ns18:externeReisendenReferenzId', '1');
141
142 2
        $tkId = $parameter->tkId;
143 2
        if (!empty($tkId)) {
144
            // with tkid
145 2
            $withTkid = $dom->createElement('ns18:mitTkid');
146 2
            $traveller->appendChild($withTkid);
147
148 2
            $withTkid->appendChild($dom->createElement('ns18:tkid', $parameter->tkId));
149 2
            $withTkid->appendChild($dom->createElement('ns18:ermaessigungsKarteCode', 'KEINE_ERMAESSIGUNGSKARTE'));
150
        } else {
151
            // without tkid, search with personal information
152
            $withoutTkid = $dom->createElement('ns18:ohneTkid');
153
            $traveller->appendChild($withoutTkid);
154
155
            $withoutTkid->appendChild($dom->createElement('ns18:reisendenTyp', 'PERSON'));
156
157
            $genderTypeId = $parameter->genderTypeId;
158
            if ($genderTypeId) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $genderTypeId of type integer|null is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
159
                $genderValue = $genderTypeId === GenderType::MEN ? 'MAENNLICH' : 'WEIBLICH';
160
                $withoutTkid->appendChild($dom->createElement('ns18:geschlecht', $genderValue));
161
            }
162
163
            $dateOfBirth = $parameter->dateOfBirth;
164
            if ($dateOfBirth !== null) {
165
                $dateOfBirthValue = $dateOfBirth->format('Y-m-d');
166
                $withoutTkid->appendChild($dom->createElement('ns18:geburtsTag', $dateOfBirthValue));
167
            }
168
169
            $withoutTkid->appendChild($dom->createElement('ns18:ermaessigungsKarteCode', 'KEINE_ERMAESSIGUNGSKARTE'));
170
        }
171
172 2
        $offerFilter = $dom->createElement('ns18:angebotsFilter');
173 2
        $methodRequest->appendChild($offerFilter);
174
175 2
        $offerFilter->setAttribute('xsi:type', 'vertriebsbase:ProduktNummerFilter');
176 2
        $offerFilter->appendChild(
177 2
            $dom->createElement('vertriebsbase:produktNummer', (string)$parameter->novaProductNumber)
178
        );
179
180 2
        if (empty($parameter->travelClass)) {
181
            throw new InvalidArgumentException('Travel class is required');
182
        }
183
184 2
        $travelClassValue = $parameter->travelClass === 1 ? 'KLASSE_1' : 'KLASSE_2';
185 2
        $methodRequest->appendChild($dom->createElement('ns18:klasse', $travelClassValue));
186
187 2
        $zoneRequest = $dom->createElement('ns18:zonenRequest');
188 2
        $methodRequest->appendChild($zoneRequest);
189
190 2
        $zoneRequest->setAttribute('ns18:tarifOwner', $parameter->tariffOwner);
191
192 2
        $zoneRequest->appendChild($dom->createElement('ns18:alleZonen', 'true'));
193
194 2
        return (string)$dom->saveXML();
195
    }
196
197
    /**
198
     * Create result object.
199
     *
200
     * @param XmlDocument $xml The xml document
201
     *
202
     * @throws DomainException
203
     *
204
     * @return NovaCreateOffersResult The mapped result
205
     */
206 2
    private function createResult(XmlDocument $xml): NovaCreateOffersResult
207
    {
208 2
        $result = new NovaCreateOffersResult();
209
210 2
        $xml = $xml->withoutNamespaces();
211
212
        // Find and append all messages
213 2
        foreach ($this->novaMessageParser->findNovaMessages($xml) as $message) {
214 2
            $result->addMessage($message);
215
        }
216
217
        // Root node
218 2
        $responseNode = $xml->queryFirstNode('/Envelope/Body/erstelleAngeboteResponse');
219 2
        $offerNodes = $xml->queryNodes('angebotsResponse/angebote/angebot', $responseNode);
220
221
        /** @var DOMElement $offerNode */
222 2
        foreach ($offerNodes as $offerNode) {
223 2
            $offer = new NovaOffer();
224
225 2
            $offerId = $offerNode->getAttribute('angebotsId');
226
227 2
            if (empty($offerId)) {
228
                throw new DomainException('SBB-NOVA offer ID not found');
229
            }
230
231 2
            $offer->novaOfferId = $offerId;
232
233 2
            $titles = [];
234
235
            // All Zones
236 2
            $titles[] = $xml->getAttributeValue(
237 2
                'nutzungsInfo/tarifStufe/tarifStufenText/@defaultWert',
238 2
                $offerNode
239
            );
240
241
            // Adults
242 2
            $titles[] = $xml->getAttributeValue(
243 2
                'produktEinflussFaktoren/kundenSegment/bezeichnung/@defaultWert',
244 2
                $offerNode
245
            );
246
247
            // Months
248 2
            $titles[] = $xml->getAttributeValue(
249 2
                'produktEinflussFaktoren/geltungsDauer/nutzungsGeltungsDauer/einheit/bezeichnung/@defaultWert',
250 2
                $offerNode
251
            );
252 2
            $title = trim(implode(', ', array_filter($titles)));
253
254 2
            $offer->title = $title;
255
256 2
            $price = $xml->getAttributeValue('verkaufsPreis/geldBetrag/@betrag', $offerNode);
257 2
            $offer->price = $price;
258
259 2
            $currency = $xml->getAttributeValue('verkaufsPreis/geldBetrag/@waehrung', $offerNode);
260
261 2
            $offer->currency = $currency;
262
263 2
            $productNumber = $offerNode->getAttribute('produktNummer');
264 2
            $offer->productNumber = $productNumber;
265
266 2
            $validFrom = $xml->getAttributeValue('nutzungsInfo/nutzungsZeitraum/ausweisbarerZeitraum/@von', $offerNode);
267 2
            $offer->validFrom = (new Chronos($validFrom))->setTime(0, 0);
268
269 2
            $validTo = $xml->getAttributeValue('nutzungsInfo/nutzungsZeitraum/ausweisbarerZeitraum/@bis', $offerNode);
270 2
            $offer->validTo = (new Chronos($validTo))->setTime(23, 59, 59);
271
272 2
            $carrierMedium = $xml->getAttributeValue('produktEinflussFaktoren/@traegerMedium', $offerNode);
273 2
            $offer->carrierMedium = $carrierMedium;
274
275 2
            $travelClass = $xml->getAttributeValue('produktEinflussFaktoren/@klasse', $offerNode);
276 2
            $offer->travelClass = $travelClass;
277
278 2
            $result->offers[] = $offer;
279
        }
280
281 2
        return $result;
282
    }
283
}
284