1: <?php
2: /**
3: * Partner API Library
4: *
5: * @copyright Copyright (c) 2020 Asseco Data Systems SA
6: * @license license.txt
7: */
8:
9: /**
10: * This is a base class for implementations of WSDL messages.
11: *
12: * This class contains some common properties and methods for all messages.
13: * It also implements "magic methods" like __call() and __get() to access
14: * messages' parts.
15: * When overridden, the new class must implement the initParts() method which
16: * should return an array containing all message's parts.
17: *
18: * @package messages
19: */
20: abstract class PartnerAPIMessage {
21:
22: /**
23: * This field defines a part name with credentials data.
24: *
25: * @var string
26: */
27: protected $partWithCredentials = NULL;
28:
29: /**
30: * This field defines a part name with a response header.
31: *
32: * @var string
33: */
34: protected $partWithResponseHeader = NULL;
35:
36: /**
37: * This field contains all parts of a message.
38: *
39: * This is an array where keys are names of a message's parts and
40: * values are objects of certain types according to the WSDL file.
41: *
42: * @var array
43: */
44: protected $parts = array();
45:
46: /**
47: * The constructor.
48: *
49: * Initiates a message's parts.
50: */
51: public function __construct() {
52: $this->parts = $this->initParts();
53: }
54:
55: /**
56: * This method returns initial data for a message's parts.
57: *
58: * This method must be redefined in overriding classes and return an array
59: * containing all parts of a message. The array keys are names of parts
60: * and the array values are objects of type according to the WSDL file.
61: * The objects must derive from the PartnerAPIType class.
62: * Example:
63: * array(
64: * 'partName' => PartnerAPITypeSomeType()
65: * )
66: *
67: * @return array A set of a message's parts
68: */
69: abstract protected function initParts();
70:
71: /**
72: * Sets the credentials data.
73: *
74: * Every request message have to contain credentials data so that
75: * the request could be authenticated. This method can be used to set
76: * the credentials.
77: * An exception of the type PartnerAPIException can be raised when
78: * the part with credentials data defined in a derived class does not exist.
79: *
80: * @param string $userName A user name
81: * @param string $password A password
82: * @return PartnerAPIMessage
83: * @throws PartnerAPIException
84: */
85: public function setCredentials($userName, $password) {
86: if (! is_null($this->partWithCredentials)) {
87: if (! isset($this->parts[$this->partWithCredentials])) {
88: require_once 'certumPartnerAPI/exceptions/exceptions.php';
89: throw new PartnerAPIException("The defined part name with credentials data '".$this->partWithCredentials."' does not exists.");
90: }
91: $element = $this->parts[$this->partWithCredentials];
92: $authToken = $element->requestHeader->authToken;
93: $authToken->setPassword($password);
94: $authToken->setUserName($userName);
95: }
96: return $this;
97: }
98:
99: /**
100: * Returns the responseHeader element from a service's response
101: *
102: * @return PartnerAPITypeResponseHeader
103: */
104: public function getResponseHeader() {
105: $partName = $this->partWithResponseHeader;
106: if (is_null($partName)) {
107: reset($this->parts);
108: $partName = key($this->parts);
109: }
110: return $this->parts[$partName]->responseHeader;
111: }
112:
113:
114: /**
115: * Returns an array with all parts and its elements
116: *
117: * The keys in this array are parts' names and values are arrays with
118: * elements belonging to a given part.
119: *
120: * The argument $omitNullValues tells if elements which value is NULL
121: * will be omitted.
122: *
123: * @param bool $omitNullValues
124: * @return array
125: */
126: public function getDataAsArray($omitNullValues = FALSE) {
127: $r = array();
128: foreach ($this->parts as $e => $p)
129: $r[$e] = $p->getDataAsArray($omitNullValues);
130: return $r;
131: }
132:
133: /**
134: * This method sets values of a message's parts.
135: *
136: * The structure of the data argument must be the same as the structure of
137: * data returned when calling an operation on an object of SoapClient class.
138: *
139: * This method, although public, is not intended to be called directly.
140: * It is rather used internally.
141: *
142: * @param array $data
143: * @return PartnerAPIMessage
144: * @throws PartnerAPIException
145: */
146: public function setData($data) {
147: if (count($this->parts) == 0) {
148: require_once 'certumPartnerAPI/exceptions/exceptions.php';
149: throw new PartnerAPIException("This message does not have any parts defined.");
150: }
151: foreach ($this->parts as $part)
152: $part->setData($data);
153: return $this;
154: }
155:
156: /**
157: * This is a "magic" method invoked when an inaccessible method is called
158: *
159: * This method supports one kind of calls:
160: * - a getting method which name must be formed like getXxx
161: * and the Xxx part of a method's name is a part name.
162: *
163: * @param string $name A name of invoked method
164: * @param array $arguments Unsed argument but required by PHP
165: * @return PartnerAPIType Actually it is an object of a type derived from the PartnerAPIType type
166: * @throws PartnerAPIException
167: */
168: public function __call($name, $arguments) {
169: if (strlen($name) <= 3) {
170: require_once 'certumPartnerAPI/exceptions/exceptions.php';
171: throw new PartnerAPIException("Invalid method name '$name' for this object.");
172: }
173: $methodType = substr($name, 0, 3);
174: if (! in_array($methodType, array('get'))) {
175: require_once 'certumPartnerAPI/exceptions/exceptions.php';
176: throw new PartnerAPIException("Invalid method name '$name' for this object.");
177: }
178: $part = $this->findPartName(substr($name, 3));
179: if (is_null($part)) {
180: require_once 'certumPartnerAPI/exceptions/exceptions.php';
181: throw new PartnerAPIException("Invalid method name '$name' for this object.");
182: }
183: if ($methodType == 'get')
184: return $this->getElement($part);
185: require_once 'certumPartnerAPI/exceptions/exceptions.php';
186: throw new PartnerAPIException("An unexpected error occurred.");
187: }
188:
189: /**
190: * Gets a part's object.
191: *
192: * This method is called by "magic" methods.
193: * It is not recommended to invoke it directly.
194: *
195: * It just return an indicated part which is an object of a type derived from
196: * PartnerAPIType.
197: *
198: * @param string $partname A part name
199: * @return object An object representing a message's part
200: */
201: protected function getPart($partname) {
202: return $this->parts[$partname];
203: }
204:
205: /**
206: * This is a "magic" method invoked when an inaccessible property is accessed.
207: *
208: * The argument $name is an accessed property and it must be a message's part name.
209: * If it does not exists an PartnerAPIException exception is raised.
210: *
211: * @param string $name A part name
212: * @return object An object representing a message's part
213: * @throws PartnerAPIException
214: */
215: public function __get($name) {
216: $part = $this->findPartName($name);
217: if (is_null($part)) {
218: require_once 'certumPartnerAPI/exceptions/exceptions.php';
219: throw new PartnerAPIException("Invalid property name '$name' for this object.");
220: }
221: return $this->getPart($part);
222: }
223:
224: /**
225: * This method converts a part's name to a proper name.
226: *
227: * It tries to find if the given part's name exists.
228: * It checks the name as it has been given, and with the first letter uppercased and lowercased.
229: * If the proper name has been found it is returned, otherwise NULL is returned.
230: *
231: * It is used by "magic" methods, so it is not so important whether an part's name
232: * is given with the first letter uppercased or lowercased. But always try to use it
233: * exactly as it is defined in WSDL file.
234: *
235: * @param string $name A part's name
236: * @return string|null A proper part's name or null
237: */
238: protected function findPartName($name) {
239: if (isset($this->parts[$name]))
240: return $name;
241: $name[0] = strtolower($name[0]);
242: if (isset($this->parts[$name]))
243: return $name;
244: $name[0] = strtoupper($name[0]);
245: if (isset($this->parts[$name]))
246: return $name;
247: return NULL;
248: }
249:
250: /**
251: * This is a "magic" method triggered by calling isset() or empty() on inaccessible properties.
252: *
253: * The argument $name is a property name and it must be a message's part name.
254: *
255: * @param string $name A part name
256: * @return bool Indicates if a property exists
257: */
258: public function __isset($name) {
259: $part = $this->findPartName($name);
260: return is_null($part) !== FALSE;
261: }
262:
263: }
264: