Completed
Push — master ( c9a3ff...e781c7 )
by Robbie
12s queued 10s
created

FederatedIdentity::__construct()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 59

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 2
dl 0
loc 59
rs 8.8945
c 0
b 0
f 0

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 SilverStripe\RealMe\Model;
4
5
use DOMDocument;
6
use DOMXPath;
7
8
use SilverStripe\ORM\FieldType\DBField;
9
use SilverStripe\View\ViewableData;
10
11
/**
12
 * Class RealMeFederatedIdentity
13
 *
14
 * Contains data to describe an identity, verified by RealMe. Provides simpler access to identity information, rather
15
 * than having to parse XML via {@link DOMDocument} or similar.
16
 *
17
 * All public methods return individual elements from the federated identity.
18
 *
19
 * Standard usage:
20
 * Injector::inst()->get('RealMeService')->enforceLogin(); // Enforce login and ensure auth data exists
21
 * $identity = Injector::inst()->get('RealMeService')->getAuthData()->getIdentity();
22
 *
23
 * Notes:
24
 * - We can't store the original DOMDocument as it's not possible to properly serialize and unserialize this such that
25
 *   it can be stored in session. Therefore, during object instantiation, we parse the XML, and store individual details
26
 *   directly against properties.
27
 *
28
 * - See this object's constructor for the XML / DOMDocument object expected to be passed during instantiation.
29
 */
30
class FederatedIdentity extends ViewableData
31
{
32
33
    /**
34
     * @var string The FIT (Federated Identity Tag) for this identity. This is the unique string that identifies an
35
     * individual, and should generally be mapped one-to-one with a {@link Member} object
36
     */
37
    private $nameId;
38
39
    /**
40
     * @var string The given first name(s) of the federated identity returned by RealMe.
41
     */
42
    public $FirstName;
43
44
    /**
45
     * @var string The given middle name(s) of the federated identity returned by RealMe.
46
     */
47
    public $MiddleName;
48
49
    /**
50
     * @var string The given last name of the federated identity returned by RealMe.
51
     */
52
    public $LastName;
53
54
    /**
55
     * @var string The gender of the federated identity returned by RealMe. Will be one of 'M', 'F', possibly 'U' or 'O'
56
     * (messaging specs are unclear).
57
     */
58
    public $Gender;
59
60
    /**
61
     * @var DOMNodeList Undocumented in RealMe messaging spec, generally describes the quality of birth info based
0 ignored issues
show
Bug introduced by
The type SilverStripe\RealMe\Model\DOMNodeList was not found. Did you mean DOMNodeList? If so, make sure to prefix the type with \.
Loading history...
62
     * presumably on the source.
63
     */
64
    public $BirthInfoQuality;
65
66
    /**
67
     * @var string The birth year of the federated identity returned by RealMe, e.g. 1993, 1954, 2015.
68
     * Probably better to use {@link getDateOfBirth()} which will return an {@link SS_Datetime} object.
69
     */
70
    public $BirthYear;
71
72
    /**
73
     * @var string The birth month of the federated identity returned by RealMe, e.g. 05 (May).
74
     * Probably better to use {@link getDateOfBirth()} which will return an {@link SS_Datetime} object.
75
     */
76
    public $BirthMonth;
77
78
    /**
79
     * @var string The birth day of the federated identity returned by RealMe, e.g. 05 (5th day of the month).
80
     * Probably better to use {@link getDateOfBirth()} which will return an {@link SS_Datetime} object.
81
     */
82
    public $BirthDay;
83
84
    /**
85
     * @var string Undocumented in RealMe messaging spec, generally describes the quality of birthplace info based
86
     * presumably on the source.
87
     */
88
    public $BirthPlaceQuality;
89
90
    /**
91
     * @var string The country of birth for the given federated identity returned by RealMe.
92
     */
93
    public $BirthPlaceCountry;
94
95
    /**
96
     * @var string The birthplace 'locality' of the federated identity returned by RealMe, e.g. 'Wellington', 'Unknown'
97
     */
98
    public $BirthPlaceLocality;
99
100
    /**
101
     * Constructor that sets the expected federated identity details based on a provided DOMDocument. The expected XML
102
     * structure for the DOMDocument is the following:
103
     *
104
     * <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
105
     * <ns1:Party
106
     *  xmlns:ns1="urn:oasis:names:tc:ciq:xpil:3"
107
     *  xmlns:ns2="urn:oasis:names:tc:ciq:ct:3"
108
     *  xmlns:ns3="urn:oasis:names:tc:ciq:xnl:3"
109
     *  xmlns:ns4="http://www.w3.org/1999/xlink"
110
     *  xmlns:ns5="urn:oasis:names:tc:ciq:xal:3">
111
     *     <ns1:PartyName>
112
     *         <ns3:PersonName>
113
     *             <ns3:NameElement ns3:ElementType="FirstName">Edmund</ns3:NameElement>
114
     *             <ns3:NameElement ns3:ElementType="MiddleName">Percival</ns3:NameElement>
115
     *             <ns3:NameElement ns3:ElementType="LastName">Hillary</ns3:NameElement>
116
     *         </ns3:PersonName>
117
     *     </ns1:PartyName>
118
     *     <ns1:PersonInfo ns1:Gender="M"/>
119
     *     <ns1:BirthInfo ns2:DataQualityType="Valid">
120
     *         <ns1:BirthInfoElement ns1:Type="BirthYear">1919</ns1:BirthInfoElement>
121
     *         <ns1:BirthInfoElement ns1:Type="BirthMonth">07</ns1:BirthInfoElement>
122
     *         <ns1:BirthInfoElement ns1:Type="BirthDay">20</ns1:BirthInfoElement>
123
     *         <ns1:BirthPlaceDetails ns2:DataQualityType="Valid">
124
     *             <ns5:Country>
125
     *                 <ns5:NameElement ns5:NameType="Name">New Zealand</ns5:NameElement>
126
     *             </ns5:Country>
127
     *             <ns5:Locality>
128
     *                 <ns5:NameElement ns5:NameType="Name">Auckland</ns5:NameElement>
129
     *             </ns5:Locality>
130
     *         </ns1:BirthPlaceDetails>
131
     *     </ns1:BirthInfo>
132
     * </ns1:Party>
133
     *
134
     * @param DOMDocument $identity
135
     * @param string $nameId
136
     */
137
    public function __construct(DOMDocument $identity, $nameId)
138
    {
139
        parent::__construct();
140
        $this->nameId = $nameId;
141
142
        $xpath = new DOMXPath($identity);
143
        $xpath->registerNamespace('p', 'urn:oasis:names:tc:ciq:xpil:3');
144
        $xpath->registerNamespace('dataQuality', 'urn:oasis:names:tc:ciq:ct:3');
145
        $xpath->registerNamespace('n', 'urn:oasis:names:tc:ciq:xnl:3');
146
        $xpath->registerNamespace('xlink', 'http://www.w3.org/1999/xlink');
147
        $xpath->registerNamespace('addr', 'urn:oasis:names:tc:ciq:xal:3');
148
149
        // Name elements
150
        $this->FirstName = $this->getNodeValue(
151
            $xpath,
152
            "/p:Party/p:PartyName/n:PersonName/n:NameElement[@n:ElementType='FirstName']"
153
        );
154
        $this->MiddleName = $this->getNodeValue(
155
            $xpath,
156
            "/p:Party/p:PartyName/n:PersonName/n:NameElement[@n:ElementType='MiddleName']"
157
        );
158
        $this->LastName = $this->getNodeValue(
159
            $xpath,
160
            "/p:Party/p:PartyName/n:PersonName/n:NameElement[@n:ElementType='LastName']"
161
        );
162
163
        // Gender
164
        $this->Gender = $this->getNamedItemNodeValue($xpath, '/p:Party/p:PersonInfo[@p:Gender]', 'Gender');
165
166
        // Birth info
167
        $this->BirthInfoQuality = $xpath->query("/p:Party/p:BirthInfo[@dataQuality:DataQualityType]");
0 ignored issues
show
Documentation Bug introduced by
It seems like $xpath->query('/p:Party/...lity:DataQualityType]') of type DOMNodeList is incompatible with the declared type SilverStripe\RealMe\Model\DOMNodeList of property $BirthInfoQuality.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
168
169
        // Birth date
170
        $this->BirthYear = $this->getNodeValue(
171
            $xpath,
172
            "/p:Party/p:BirthInfo/p:BirthInfoElement[@p:Type='BirthYear']"
173
        );
174
        $this->BirthMonth = $this->getNodeValue(
175
            $xpath,
176
            "/p:Party/p:BirthInfo/p:BirthInfoElement[@p:Type='BirthMonth']"
177
        );
178
        $this->BirthDay = $this->getNodeValue(
179
            $xpath,
180
            "/p:Party/p:BirthInfo/p:BirthInfoElement[@p:Type='BirthDay']"
181
        );
182
183
        // Birth place
184
        $this->BirthPlaceQuality = $this->getNamedItemNodeValue(
185
            $xpath,
186
            '/p:Party/p:BirthInfo/p:BirthPlaceDetails[@dataQuality:DataQualityType]',
187
            'DataQualityType'
188
        );
189
        $this->BirthPlaceCountry = $this->getNodeValue(
190
            $xpath,
191
            "/p:Party/p:BirthInfo/p:BirthPlaceDetails/addr:Country/addr:NameElement[@addr:NameType='Name']"
192
        );
193
        $this->BirthPlaceLocality = $this->getNodeValue(
194
            $xpath,
195
            "/p:Party/p:BirthInfo/p:BirthPlaceDetails/addr:Locality/addr:NameElement[@addr:NameType='Name']"
196
        );
197
    }
198
199
    public function isValid()
200
    {
201
        return true;
202
    }
203
204
    public function getDateOfBirth()
205
    {
206
        if ($this->BirthYear && $this->BirthMonth && $this->BirthDay) {
207
            $value = sprintf('%d-%d-%d', $this->BirthYear, $this->BirthMonth, $this->BirthDay);
208
            return DBField::create_field('SS_DateTime', $value);
209
        } else {
210
            return null;
211
        }
212
    }
213
214
    /**
215
     * @param DOMXPath $xpath The DOMXPath object to carry out the query on
216
     * @param string $query The XPath query to find the relevant node
217
     * @param string $namedAttr The named attribute to retrieve from the XPath query
218
     * @return string|null Either the value from the named item, or null if no item exists
219
     */
220
    private function getNamedItemNodeValue(DOMXPath $xpath, $query, $namedAttr)
221
    {
222
        $query = $xpath->query($query);
223
        $value = null;
224
225
        if ($query->length > 0) {
226
            $item = $query->item(0);
227
228
            if ($item->hasAttributes()) {
229
                $value = $item->attributes->getNamedItem($namedAttr);
230
231
                if (strlen($value->nodeValue) > 0) {
232
                    $value = $value->nodeValue;
233
                }
234
            }
235
        }
236
237
        return $value;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $value also could return the type DOMNode which is incompatible with the documented return type null|string.
Loading history...
238
    }
239
240
    /**
241
     * @param DOMXPath $xpath The DOMXPath object to carry out the query on
242
     * @param string $query The XPath query to find the relevant node
243
     * @return string|null Either the first matching node's value (there should only ever be one), or null if none found
244
     */
245
    private function getNodeValue(DOMXPath $xpath, $query)
246
    {
247
        $query = $xpath->query($query);
248
        return ($query->length > 0 ? $query->item(0)->nodeValue : null);
249
    }
250
}
251