Completed
Push — master ( 3a7943...bccb03 )
by Nicolaas
03:04
created

EcommercePayment::i18n_plural_name()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * "Abstract" class for a number of different payment
4
 * types allowing a user to pay for something on a site.
5
 *
6
 *
7
 * This can't be an abstract class because sapphire doesn't
8
 * support abstract DataObject classes.
9
 */
10
class EcommercePayment extends DataObject implements EditableEcommerceObject
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
11
{
12
    /**
13
     * standard SS Variable.
14
     *
15
     * @var array
16
     */
17
    private static $dependencies = array(
0 ignored issues
show
Unused Code introduced by
The property $dependencies is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
18
        'supportedMethodsProvider' => '%$EcommercePaymentSupportedMethodsProvider',
19
    );
20
21
    /**
22
     * automatically populated by the dependency manager.
23
     *
24
     * @var EcommercePaymentSupportedMethodsProvider
25
     */
26
    public $supportedMethodsProvider = null;
27
28
    /**
29
     * Incomplete (default): Payment created but nothing confirmed as successful
30
     * Success: Payment successful
31
     * Failure: Payment failed during process
32
     * Pending: Payment awaiting receipt/bank transfer etc.
33
     */
34
    private static $db = array(
0 ignored issues
show
Unused Code introduced by
The property $db is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
35
        'Status' => "Enum('Incomplete,Success,Failure,Pending','Incomplete')",
36
        'Amount' => 'Money',
37
        'Message' => 'Text',
38
        'IP' => 'Varchar(45)', /* for IPv6 you have to make sure you have up to 45 characters */
39
        'ProxyIP' => 'Varchar(45)',
40
        'ExceptionError' => 'Text',
41
    );
42
43
    private static $has_one = array(
0 ignored issues
show
Unused Code introduced by
The property $has_one is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
44
        'PaidBy' => 'Member',
45
        'Order' => 'Order',
46
    );
47
48
    private static $summary_fields = array(
0 ignored issues
show
Unused Code introduced by
The property $summary_fields is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
49
        'Created' => 'Created',
50
        'Order.Title' => "Order",
51
        'Title' => 'Type',
52
        'AmountCurrency' => 'Amount',
53
        'Amount.Nice' => 'Amount',
54
        'Status' => 'Status',
55
    );
56
57
    private static $casting = array(
0 ignored issues
show
Unused Code introduced by
The property $casting is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
58
        'Title' => 'Varchar',
59
        'AmountValue' => 'Currency',
60
        'AmountCurrency' => 'Varchar',
61
    );
62
63
    private static $searchable_fields = array(
0 ignored issues
show
Unused Code introduced by
The property $searchable_fields is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
64
        'OrderID' => array(
65
            'field' => 'NumericField',
66
            'title' => 'Order Number',
67
        ),
68
        'Created' => array(
69
            'title' => 'Date (e.g. today)',
70
            'field' => 'TextField',
71
            'filter' => 'EcommercePaymentFilters_AroundDateFilter',
72
        ),
73
        'IP' => array(
74
            'title' => 'IP Address',
75
            'filter' => 'PartialMatchFilter',
76
        ),
77
        'Status',
78
    );
79
80
    /**
81
     * standard SS variable.
82
     *
83
     * @Var String
84
     */
85
    private static $singular_name = 'Shop Payment';
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
Unused Code introduced by
The property $singular_name is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
86
    public function i18n_singular_name()
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
87
    {
88
        return $this->Config()->get('singular_name');
89
    }
90
91
    /**
92
     * standard SS variable.
93
     *
94
     * @Var String
95
     */
96
    private static $plural_name = 'Shop Payments';
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
Unused Code introduced by
The property $plural_name is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
97
    public function i18n_plural_name()
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
98
    {
99
        return $this->Config()->get('plural_name');
100
    }
101
102
103
    /**
104
     * CRUCIAL
105
     * makes sure all the relevant payment methods are available ...
106
     *
107
     * @return this | EcommercePayment
0 ignored issues
show
Documentation introduced by
Should the return type not be EcommercePayment?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
108
     */
109
    public function init()
110
    {
111
        self::get_supported_methods($this->Order());
0 ignored issues
show
Documentation Bug introduced by
The method Order does not exist on object<EcommercePayment>? 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...
112
        return $this;
113
    }
114
115
    /**
116
     * standard SS variable.
117
     *
118
     * @var string
119
     */
120
    private static $default_sort = '"Created" DESC';
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
Unused Code introduced by
The property $default_sort is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
121
122
    public function getCMSFields()
123
    {
124
        $fields = parent::getCMSFields();
125
        $fields->replaceField('OrderID', new ReadonlyField('OrderID', 'Order ID'));
126
        $fields->replaceField('PaidByID', new ReadonlyField('PaidByID', 'Payment made by'));
127
128
        return $fields;
129
    }
130
131
    /**
132
     * link to edit the record.
133
     *
134
     * @param string | Null $action - e.g. edit
135
     *
136
     * @return string
137
     */
138
    public function CMSEditLink($action = null)
139
    {
140
        return CMSEditLinkAPI::find_edit_link_for_object($this, $action);
141
    }
142
143
    /**
144
     * Standard SS method.
145
     *
146
     * @param Member $member
0 ignored issues
show
Documentation introduced by
Should the type for parameter $member not be Member|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
147
     *
148
     * @return bool
0 ignored issues
show
Documentation introduced by
Should the return type not be boolean|string|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
149
     */
150
    public function canCreate($member = null)
151
    {
152
        if (! $member) {
153
            $member = Member::currentUser();
154
        }
155
        $extended = $this->extendedCan(__FUNCTION__, $member);
0 ignored issues
show
Documentation introduced by
$member is of type object<DataObject>|null, but the function expects a object<Member>|integer.

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...
156
        if ($extended !== null) {
157
            return $extended;
158
        }
159
        if (Permission::checkMember($member, Config::inst()->get('EcommerceRole', 'admin_permission_code'))) {
160
            return true;
161
        }
162
163
        return parent::canCreate($member);
0 ignored issues
show
Bug introduced by
It seems like $member defined by \Member::currentUser() on line 153 can also be of type object<DataObject>; however, DataObject::canCreate() does only seem to accept object<Member>|null, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
164
    }
165
166
    public function canView($member = null)
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
167
    {
168
        if (! $member) {
169
            $member = Member::currentUser();
170
        }
171
        $extended = $this->extendedCan(__FUNCTION__, $member);
172
        if ($extended !== null) {
173
            return $extended;
174
        }
175
        $order = $this->Order();
0 ignored issues
show
Documentation Bug introduced by
The method Order does not exist on object<EcommercePayment>? 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...
176
        if ($order && $order->exists()) {
177
            return $order->canView();
178
        }
179
        if (Permission::checkMember($member, Config::inst()->get('EcommerceRole', 'admin_permission_code'))) {
180
            return true;
181
        }
182
183
        return parent::canCreate($member);
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (canCreate() instead of canView()). Are you sure this is correct? If so, you might want to change this to $this->canCreate().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
184
    }
185
186
    /**
187
     * Standard SS method.
188
     *
189
     * @param Member $member
0 ignored issues
show
Documentation introduced by
Should the type for parameter $member not be Member|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
190
     *
191
     * @return bool
0 ignored issues
show
Documentation introduced by
Should the return type not be boolean|string|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
192
     */
193
    public function canEdit($member = null)
194
    {
195
        if (! $member) {
196
            $member = Member::currentUser();
197
        }
198
        if ($this->Status == 'Pending' || $this->Status == 'Incomplete') {
0 ignored issues
show
Documentation introduced by
The property Status does not exist on object<EcommercePayment>. 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...
199
            $extended = $this->extendedCan(__FUNCTION__, $member);
0 ignored issues
show
Documentation introduced by
$member is of type object<DataObject>|null, but the function expects a object<Member>|integer.

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...
200
            if ($extended !== null) {
201
                return $extended;
202
            }
203
            if (Permission::checkMember($member, Config::inst()->get('EcommerceRole', 'admin_permission_code'))) {
204
                return true;
205
            }
206
207
            return parent::canEdit($member);
0 ignored issues
show
Bug introduced by
It seems like $member defined by \Member::currentUser() on line 196 can also be of type object<DataObject>; however, DataObject::canEdit() does only seem to accept object<Member>|null, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
208
        }
209
210
        return false;
211
    }
212
213
    /**
214
     * Standard SS method
215
     * set to false as a security measure...
216
     *
217
     * @param Member $member
0 ignored issues
show
Documentation introduced by
Should the type for parameter $member not be Member|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
218
     *
219
     * @return bool
220
     */
221
    public function canDelete($member = null)
222
    {
223
        return false;
224
    }
225
226
    /**
227
     * redirect to order action.
228
     */
229
    public function redirectToOrder()
230
    {
231
        $order = $this->Order();
0 ignored issues
show
Documentation Bug introduced by
The method Order does not exist on object<EcommercePayment>? 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...
232
        if ($order) {
233
            Controller::curr()->redirect($order->Link());
234
        } else {
235
            user_error('No order found with this payment: '.$this->ID, E_USER_NOTICE);
236
        }
237
238
        return;
239
    }
240
241
    /**
242
     * alias
243
     * @return string
244
     */
245
    public function Title()
246
    {
247
        return $this->getTitle();
248
    }
249
250
    /**
251
     * @return string
252
     */
253
    public function getTitle()
254
    {
255
        return $this->i18n_singular_name();
256
    }
257
258
    /**
259
     * alias for getAmountValue
260
     * @return float
261
     */
262
    public function AmountValue()
263
    {
264
        return $this->getAmountValue();
265
    }
266
267
    /**
268
     * @return float
269
     */
270
    public function getAmountValue()
271
    {
272
        return $this->Amount->getAmount();
0 ignored issues
show
Documentation introduced by
The property Amount does not exist on object<EcommercePayment>. 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...
273
    }
274
275
    /**
276
     * alias for getAmountCurrency
277
     * @return string
278
     */
279
    public function AmountCurrency()
280
    {
281
        return $this->getAmountCurrency();
282
    }
283
284
    /**
285
     * @return string
286
     */
287
    public function getAmountCurrency()
288
    {
289
        return $this->Amount->getCurrency();
0 ignored issues
show
Documentation introduced by
The property Amount does not exist on object<EcommercePayment>. 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...
290
    }
291
292
    /**
293
     * standard SS method
294
     * try to finalise order if payment has been made.
295
     */
296
    public function onBeforeWrite()
297
    {
298
        parent::onBeforeWrite();
299
        $this->PaidByID = Member::currentUserID();
0 ignored issues
show
Documentation introduced by
The property PaidByID does not exist on object<EcommercePayment>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write 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.");
        }
    }

}

Since the property has write access only, you can use the @property-write 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...
300
    }
301
302
    /**
303
     * standard SS method
304
     * try to finalise order if payment has been made.
305
     */
306
    public function onAfterWrite()
307
    {
308
        parent::onAfterWrite();
309
        $order = $this->Order();
0 ignored issues
show
Documentation Bug introduced by
The method Order does not exist on object<EcommercePayment>? 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...
310
        if ($order && is_a($order, Object::getCustomClass('Order')) && $order->IsSubmitted()) {
311
            $order->tryToFinaliseOrder();
312
        }
313
    }
314
315
    /**
316
     *@return string
317
     **/
318
    public function Status()
319
    {
320
        return _t('Payment.'.strtoupper($this->Status), $this->Status);
0 ignored issues
show
Documentation introduced by
The property Status does not exist on object<EcommercePayment>. 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...
321
    }
322
323
    /**
324
     * Return the site currency in use.
325
     *
326
     * @return string
0 ignored issues
show
Documentation introduced by
Should the return type not be array|integer|double|string|boolean?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
327
     */
328
    public static function site_currency()
329
    {
330
        $currency = EcommerceConfig::get('EcommerceCurrency', 'default_currency');
331
        if (!$currency) {
332
            user_error('It is highly recommended that you set a default currency using the config files (EcommerceCurrency.default_currency)', E_USER_NOTICE);
333
        }
334
335
        return $currency;
336
    }
337
338
    /**
339
     * Set currency to default one.
340
     * Set IP address.
341
     */
342
    public function populateDefaults()
343
    {
344
        parent::populateDefaults();
345
        $this->Amount->Currency = EcommerceConfig::get('EcommerceCurrency', 'default_currency');
0 ignored issues
show
Documentation introduced by
The property Amount does not exist on object<EcommercePayment>. 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...
346
        $this->setClientIP();
347
    }
348
349
    /**
350
     * Set the IP address of the user to this payment record.
351
     * This isn't perfect - IP addresses can be hidden fairly easily.
352
     */
353
    protected function setClientIP()
0 ignored issues
show
Coding Style introduced by
setClientIP uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

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

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
354
    {
355
        $proxy = null;
356
        $ip = null;
357
        if (Controller::has_curr()) {
358
            $ip = Controller::curr()->getRequest()->getIP();
359
        }
360
361
        if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
362
            //swapsies
363
            $proxy = $ip;
364
        }
365
366
        // Only set the IP and ProxyIP if none currently set
367
        if (! $this->IP) {
0 ignored issues
show
Documentation introduced by
The property IP does not exist on object<EcommercePayment>. 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...
368
            $this->IP = $ip;
0 ignored issues
show
Documentation introduced by
The property IP does not exist on object<EcommercePayment>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write 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.");
        }
    }

}

Since the property has write access only, you can use the @property-write 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...
369
        }
370
        if (! $this->ProxyIP) {
0 ignored issues
show
Documentation introduced by
The property ProxyIP does not exist on object<EcommercePayment>. 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...
371
            $this->ProxyIP = $proxy;
0 ignored issues
show
Documentation introduced by
The property ProxyIP does not exist on object<EcommercePayment>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write 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.");
        }
    }

}

Since the property has write access only, you can use the @property-write 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...
372
        }
373
    }
374
375
    /**
376
     * Returns the Payment type currently in use.
377
     *
378
     * @return string | null
379
     */
380
    public function PaymentMethod()
381
    {
382
        $supportedMethods = self::get_supported_methods($this->Order());
0 ignored issues
show
Documentation Bug introduced by
The method Order does not exist on object<EcommercePayment>? 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...
383
        if (isset($supportedMethods[$this->ClassName])) {
384
            return $supportedMethods[$this->ClassName];
385
        }
386
    }
387
388
    /**
389
     * Static method to quickly update the payment method on runtime
390
     * associative array that goes like ClassName => Description ...
391
     *
392
     * e.g. MyPaymentClass => Best Payment Method Ever	 * @param array $array -
393
     * @param array $array
394
     */
395
    public static function set_supported_methods($array)
396
    {
397
        Config::inst()->update('EcommercePayment', 'supported_methods', null);
398
        Config::inst()->update('EcommercePayment', 'supported_methods', $array);
399
    }
400
401
    /**
402
     * returns the list of supported methods
403
     * test methods are included if the site is in DEV mode OR
404
     * the current user is a ShopAdmin.
405
     *
406
     * @return array
0 ignored issues
show
Documentation introduced by
Should the return type not be array|integer|double|string|boolean?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
407
     *     [Code] => "Description",
408
     *     [Code] => "Description",
409
     *     [Code] => "Description"
410
     */
411
    public static function get_supported_methods($order = null)
412
    {
413
        $obj = self::create();
414
        return $obj->supportedMethodsProvider->SupportedMethods($order);
415
    }
416
417
    /**
418
     * Return the form requirements for all the payment methods.
419
     *
420
     * @param null | Array
421
     *
422
     * @return An array suitable for passing to CustomRequiredFields
0 ignored issues
show
Documentation introduced by
Should the return type not be An|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
423
     */
424
    public static function combined_form_requirements($order = null)
0 ignored issues
show
Unused Code introduced by
The parameter $order is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
425
    {
426
        return;
427
    }
428
429
    /**
430
     * Return a set of payment fields from all enabled
431
     * payment methods for this site, given the .
432
     * is used to define which methods are available.
433
     *
434
     * @param string       $amount formatted amount (e.g. 12.30) without the currency
435
     * @param null | Order $order
436
     *
437
     * @return FieldList
438
     */
439
    public static function combined_form_fields($amount, $order = null)
440
    {
441
        // Create the initial form fields, which defines an OptionsetField
442
        // allowing the user to choose which payment method to use.
443
        $supportedMethods = self::get_supported_methods($order);
444
        $fields = new FieldList(
445
            new OptionsetField(
446
                'PaymentMethod',
447
                '',
448
                $supportedMethods
449
            )
450
        );
451
        foreach ($supportedMethods as $methodClass => $methodName) {
0 ignored issues
show
Bug introduced by
The expression $supportedMethods of type array|integer|double|string|boolean is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
452
            // Create a new CompositeField with method specific fields,
453
            // as defined on each payment method class using getPaymentFormFields()
454
            $methodFields = new CompositeField($methodClass::create()->getPaymentFormFields());
455
            $methodFields->addExtraClass("methodFields_$methodClass");
456
            $methodFields->addExtraClass('paymentfields');
457
            // Add those fields to the initial FieldSet we first created
458
            $fields->push($methodFields);
459
        }
460
461
        // Add the amount and subtotal fields for the payment amount
462
        $fields->push(new HeaderField('Amount', _t('Payment.AMOUNT_COLON', 'Amount to be charged: ').'<u class="totalAmountToBeCharged">'.$amount.'</u>', 4));
463
464
        return $fields;
465
    }
466
467
    /**
468
     * Return the payment form fields that should
469
     * be shown on the checkout order form for the
470
     * payment type. Example: for {@link DPSPayment},
471
     * this would be a set of fields to enter your
472
     * credit card details.
473
     *
474
     * @return FieldList
0 ignored issues
show
Documentation introduced by
Should the return type not be FieldList|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
475
     */
476
    public function getPaymentFormFields()
477
    {
478
        user_error("Please implement getPaymentFormFields() on $this->class", E_USER_ERROR);
479
    }
480
481
    /**
482
     * Define what fields defined in {@link Order->getPaymentFormFields()}
483
     * should be required.
484
     *
485
     * @see DPSPayment->getPaymentFormRequirements() for an example on how
486
     * this is implemented.
487
     *
488
     * @return array
0 ignored issues
show
Documentation introduced by
Should the return type not be array|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
489
     */
490
    public function getPaymentFormRequirements()
491
    {
492
        user_error("Please implement getPaymentFormRequirements() on $this->class", E_USER_ERROR);
493
    }
494
495
    /**
496
     * Checks if all the data for payment is correct (e.g. credit card)
497
     * By default it returns true, because lots of payments gatewawys
498
     * do not have any fields required here.
499
     *
500
     * @param array     $data The form request data - see OrderForm
501
     * @param OrderForm $form The form object submitted on
502
     */
503
    public function validatePayment($data, $form)
0 ignored issues
show
Unused Code introduced by
The parameter $data is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $form is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
504
    {
505
        return true;
506
    }
507
508
    /**
509
     * Perform payment processing for the type of
510
     * payment. For example, if this was a credit card
511
     * payment type, you would perform the data send
512
     * off to the payment gateway on this function for
513
     * your payment subclass.
514
     *
515
     * This is used by {@link OrderForm} when it is
516
     * submitted.
517
     *
518
     * @param array     $data The form request data - see OrderForm
519
     * @param OrderForm $form The form object submitted on
520
     *
521
     * @return EcommercePayment_Result
0 ignored issues
show
Documentation introduced by
Should the return type not be EcommercePayment_Result|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
522
     */
523
    public function processPayment($data, $form)
0 ignored issues
show
Unused Code introduced by
The parameter $data is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $form is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
524
    {
525
        user_error("Please implement processPayment() on $this->class", E_USER_ERROR);
526
    }
527
528
    protected function handleError($e)
529
    {
530
        $this->ExceptionError = $e->getMessage();
0 ignored issues
show
Documentation introduced by
The property ExceptionError does not exist on object<EcommercePayment>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write 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.");
        }
    }

}

Since the property has write access only, you can use the @property-write 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...
531
        $this->write();
532
    }
533
534
    public function PaidObject()
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
535
    {
536
        return $this->Order();
0 ignored issues
show
Documentation Bug introduced by
The method Order does not exist on object<EcommercePayment>? 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...
537
    }
538
539
    /**
540
     * Debug helper method.
541
     * Access through : /shoppingcart/debug/.
542
     */
543
    public function debug()
544
    {
545
        $html = EcommerceTaskDebugCart::debug_object($this);
546
547
        return $html;
548
    }
549
550
    /**
551
     * LEGACY METHOD
552
     * Process payment form and return next step in the payment process.
553
     * Steps taken are:
554
     * 1. create new payment
555
     * 2. save form into payment
556
     * 3. return payment result.
557
     *
558
     * @param Order $order - the order that is being paid
559
     * @param Form  $form  - the form that is being submitted
560
     * @param array $data  - Array of data that is submittted
561
     *
562
     * @return bool - if successful, this method will return TRUE
563
     */
564
    public static function process_payment_form_and_return_next_step($order, $data, $form)
565
    {
566
        $formHelper = $this->ecommercePaymentFormSetupAndValidationObject();
0 ignored issues
show
Bug introduced by
The variable $this does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
567
568
        return $formHelper->processPaymentFormAndReturnNextStep($order, $data, $form);
569
    }
570
571
    /**
572
     * LEGACY METHOD.
573
     *
574
     * @param Order $order - the order that is being paid
575
     * @param array $data  - Array of data that is submittted
576
     * @param Form  $form  - the form that is being submitted
577
     *
578
     * @return bool - true if the data is valid
579
     */
580
    public static function validate_payment($order, $data, $form)
581
    {
582
        $formHelper = $this->ecommercePaymentFormSetupAndValidationObject();
0 ignored issues
show
Bug introduced by
The variable $this does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
583
584
        return $formHelper->validatePayment($order, $data, $form);
585
    }
586
587
    private $ecommercePaymentFormSetupAndValidationObject = null;
588
589
    /**
590
     * @return EcommercePaymentFormSetupAndValidation
591
     */
592
    protected function ecommercePaymentFormSetupAndValidationObject()
593
    {
594
        if (!$this->ecommercePaymentFormSetupAndValidationObject) {
595
            $this->ecommercePaymentFormSetupAndValidationObject = Injector::inst()->create('EcommercePaymentFormSetupAndValidation');
596
        }
597
598
        return $this->ecommercePaymentFormSetupAndValidationObject;
599
    }
600
601
    /**
602
     * @return EcommercePaymentFormSetupAndValidation
603
     */
604
    public static function ecommerce_payment_form_setup_and_validation_object()
605
    {
606
        return Injector::inst()->create('EcommercePaymentFormSetupAndValidation');
607
    }
608
}
609