PaymentService::set_http_request()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 3
rs 10
cc 1
eloc 2
nc 1
nop 1
1
<?php
2
3
/**
4
 * Payment Service
5
 *
6
 * Provides wrapper methods for interacting with the omnipay gateways
7
 * library.
8
 *
9
 * Interfaces with the omnipay library
10
 *
11
 * @package payment
12
 */
13
14
use Omnipay\Common\GatewayFactory;
15
use Omnipay\Common\Message\AbstractResponse;
16
use Omnipay\Common\Message\AbstractRequest;
17
18
abstract class PaymentService extends Object{
19
20
	/**
21
	 * @var Guzzle\Http\ClientInterface
22
	 */	
23
	private static $httpclient;
24
	
25
	/**
26
	 * @var Guzzle\Http\Message\Request
27
	 */	
28
	private static $httprequest;
29
30
	/**
31
	 * @var Payment
32
	 */
33
	protected $payment;
34
35
	/**
36
	 * @var String
37
	 */
38
	protected $returnurl;
39
	
40
	/**
41
	 * @var String
42
	 */
43
	protected $cancelurl;
44
	
45
	/**
46
	 * @var Guzzle\Http\Message\Response
47
	 */
48
	protected $response;
49
50
	/**
51
	 * @param Payment
52
	 */
53
	public function __construct(Payment $payment) {
54
		$this->payment = $payment;
55
	}
56
57
	/**
58
	 * Get the url to return to, that has been previously stored.
59
	 * This is not a database field.
60
	 * @return string the url
61
	 */
62
	public function getReturnUrl() {
63
		return $this->returnurl;
64
	}
65
66
	/**
67
	 * Set the url to redirect to after payment is made/attempted.
68
	 * This function also populates the cancel url, if it is empty.
69
	 * @return PaymentService this object for chaining
70
	 */
71
	public function setReturnUrl($url) {
72
		$this->returnurl = $url;
73
		if (!$this->cancelurl) {
74
			$this->cancelurl = $url;
75
		}
76
77
		return $this;
78
	}
79
80
	/**
81
	 * @return string cancel url
82
	 */
83
	public function getCancelUrl() {
84
		return $this->cancelurl;
85
	}
86
87
	/**
88
	 * Set the url to redirect to after payment is cancelled
89
	 * @return PaymentService this object for chaining
90
	 */
91
	public function setCancelUrl($url) {
92
		$this->cancelurl = $url;
93
94
		return $this;
95
	}
96
97
	/**
98
	 * Get the appropriate redirect url
99
	 */
100
	public function getRedirectURL() {
101
		if ($this->response) {
102
			if ($this->response->isSuccessful()) {
103
				return $this->getReturnUrl();
104
			} elseif ($this->response->isRedirect()) {
105
				return $this->response->getRedirectUrl();
0 ignored issues
show
Bug introduced by
The method getRedirectUrl() does not seem to exist on object<Guzzle\Http\Message\Response>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
106
			}
107
		}
108
109
		return $this->getCancelUrl();
110
	}
111
112
	/**
113
	 * Update class properties via array.
114
	 */
115
	public function update($data) {
116
		if(isset($data['returnUrl'])){
117
			$this->setReturnUrl($data['returnUrl']);
118
		}
119
		if(isset($data['cancelUrl'])){
120
			$this->setCancelUrl($data['cancelUrl']);
121
		}
122
	}
123
124
125
	/**
126
	 * Get the omnipay gateway associated with this payment,
127
	 * with configuration applied.
128
	 *
129
	 * @throws RuntimeException - when gateway doesn't exist.
130
	 * @return AbstractGateway omnipay gateway class
131
	 */
132
	public function oGateway() {
133
		$factory = new GatewayFactory;
134
		$gateway = $factory->create(
135
			$this->payment->Gateway,
0 ignored issues
show
Documentation introduced by
The property Gateway does not exist on object<Payment>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
136
			self::$httpclient,
137
			self::$httprequest
0 ignored issues
show
Documentation introduced by
self::$httprequest is of type object<Guzzle\Http\Message\Request>, but the function expects a null|object<Symfony\Comp...HttpFoundation\Request>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
138
		);
139
		$parameters = Config::inst()->forClass('Payment')->parameters;
140
		if (isset($parameters[$this->payment->Gateway])) {
0 ignored issues
show
Documentation introduced by
The property Gateway does not exist on object<Payment>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
141
			$gateway->initialize($parameters[$this->payment->Gateway]);
0 ignored issues
show
Documentation introduced by
The property Gateway does not exist on object<Payment>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
142
		}
143
144
		return $gateway;
145
	}
146
147
	/**
148
	 * Generate a return/notify url for off-site gateways (completePayment).
149
	 * @return string endpoint url
150
	 */
151
	protected function getEndpointURL($action, $identifier) {
152
		return PaymentGatewayController::get_endpoint_url($action, $identifier);
153
	}
154
155
	/**
156
	 * Record a transaction on this for this payment.
157
	 * @param string $type the type of transaction to create.
158
	 *        This is any class that is (or extends) PaymentMessage.
159
	 * @param array|string|AbstractResponse|AbstractRequest|OmnipayException $data the response to record, or data to store
160
	 * @return GatewayTransaction newly created dataobject, saved to database.
161
	 */
162
	protected function createMessage($type, $data = null) {
163
		$output = array();
164
		if (is_string($data)) {
165
			$output =  array(
166
				'Message' => $data
167
			);
168
		} elseif (is_array($data)) {
169
			$output = $data;
170
		} elseif ($data instanceof Omnipay\Common\Exception\OmnipayException) {
171
			$output = array(
172
				"Message" => $data->getMessage(),
173
				"Code" => $data->getCode(),
174
				"Exception" => get_class($data),
175
				"Backtrace" => $data->getTraceAsString()
176
			);
177
		} elseif ($data instanceof AbstractResponse) {
178
			$output =  array(
179
				"Message" => $data->getMessage(),
180
				"Code" => $data->getCode(),
181
				"Reference" => $data->getTransactionReference(),
182
				"Data" => $data->getData()
183
			);
184
		} elseif ($data instanceof AbstractRequest) {
185
			$output = array(
186
				'Token' => $data->getToken(),
187
				'CardReference' => $data->getCardReference(),
188
				'Amount' => $data->getAmount(),
189
				'Currency' => $data->getCurrency(),
190
				'Description' => $data->getDescription(),
191
				'TransactionId' => $data->getTransactionId(),
192
				'TransactionReference' => $data->getTransactionReference(),
193
				'ClientIp' => $data->getClientIp(),
194
				'ReturnUrl' => $data->getReturnUrl(),
195
				'CancelUrl' => $data->getCancelUrl(),
196
				'NotifyUrl' => $data->getNotifyUrl(),
197
				'Parameters' => $data->getParameters()
198
			);
199
		}
200
		$output = array_merge($output, array(
201
			"PaymentID" => $this->payment->ID,
202
			"Gateway" => $this->payment->Gateway
0 ignored issues
show
Documentation introduced by
The property Gateway does not exist on object<Payment>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
203
		));
204
		$this->logToFile($output, $type);
205
		$message = $type::create($output);
206
		$message->write();
207
		$this->payment->Messages()->add($message);
0 ignored issues
show
Documentation Bug introduced by
The method Messages does not exist on object<Payment>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
208
209
		return $message;
210
	}
211
212
	/**
213
	 * Helper function for logging gateway requests
214
	 */
215
	protected function logToFile($data, $type = "") {
216
		if($logstyle = Payment::config()->file_logging){
217
			$title = $type." (".$this->payment->Gateway.")";
0 ignored issues
show
Documentation introduced by
The property Gateway does not exist on object<Payment>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
218
			if ($logstyle === "verbose") {
219
				Debug::log(
220
					$title."\n\n".
221
					print_r($data, true)
222
				);
223
			} elseif($logstyle) {
224
				Debug::log(implode(", ", array(
225
					$title,
226
					isset($data['Message']) ? $data['Message'] : " ",
227
					isset($data['Code']) ? $data['Code'] : " ",
228
				)));
229
			}
230
		}
231
	}
232
233
	protected function createGatewayResponse() {
234
		$gatewayresponse = new GatewayResponse($this->payment);
235
		$gatewayresponse->setRedirectURL($this->getRedirectURL());
236
		return $gatewayresponse;
237
	}
238
239
	//testing functions (could these instead be injected somehow?)
240
241
	/**
242
	 * Set the guzzle client (for testing)
243
	 * @param Guzzle\Http\ClientInterface $httpClient guzzle client for testing
244
	 */
245
	public static function set_http_client(Guzzle\Http\ClientInterface $httpClient) {
246
		self::$httpclient = $httpClient;
247
	}
248
249
	public static function get_http_client() {
250
		return self::$httpclient;
251
	}
252
253
	/**
254
	 * Set the symphony http request (for testing)
255
	 * @param Symfony\Component\HttpFoundation\Request $httpRequest symphony http request for testing
256
	 */
257
	public static function set_http_request(Symfony\Component\HttpFoundation\Request $httpRequest) {
0 ignored issues
show
Bug introduced by
You have injected the Request via parameter $httpRequest. This is generally not recommended as there might be multiple instances during a request cycle (f.e. when using sub-requests). Instead, it is recommended to inject the RequestStack and retrieve the current request each time you need it via getCurrentRequest().
Loading history...
258
		self::$httprequest = $httpRequest;
0 ignored issues
show
Documentation Bug introduced by
It seems like $httpRequest of type object<Symfony\Component\HttpFoundation\Request> is incompatible with the declared type object<Guzzle\Http\Message\Request> of property $httprequest.

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...
259
	}
260
261
	public static function get_http_request() {
262
		return self::$httprequest;
263
	}
264
265
}
266