EcommerceCurrency   F
last analyzed

Complexity

Total Complexity 93

Size/Duplication

Total Lines 776
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 20

Importance

Changes 0
Metric Value
dl 0
loc 776
rs 1.824
c 0
b 0
f 0
wmc 93
lcom 2
cbo 20

40 Methods

Rating   Name   Duplication   Size   Complexity  
A i18n_singular_name() 0 4 1
A i18n_plural_name() 0 4 1
A canCreate() 0 15 4
A canView() 0 15 4
A canEdit() 0 15 4
A canDelete() 0 19 6
A ecommerce_currency_list() 0 17 2
A get_list() 0 12 1
B get_money_object_from_order_currency() 0 32 10
A default_currency() 0 10 1
A default_currency_code() 0 15 4
A default_currency_id() 0 6 2
A get_one_from_code() 0 10 1
A getCMSFields() 0 22 2
A CMSEditLink() 0 4 1
A DefaultSymbol() 0 4 1
A getDefaultSymbol() 0 4 1
A ShortSymbol() 0 4 1
A getShortSymbol() 0 4 1
A LongSymbol() 0 4 1
A getLongSymbol() 0 4 1
A IsDefault() 0 4 1
A getIsDefault() 0 11 3
A IsDefaultNice() 0 4 1
A getIsDefaultNice() 0 8 2
A InUseNice() 0 4 1
A getInUseNice() 0 8 2
A ExchangeRate() 0 4 1
A getExchangeRate() 0 7 1
A ExchangeRateExplanation() 0 4 1
A getExchangeRateExplanation() 0 11 2
A IsCurrent() 0 6 2
A Link() 0 4 1
A LinkingMode() 0 14 3
B validate() 0 25 8
A populateDefaults() 0 5 1
A onBeforeWrite() 0 12 5
A requireDefaultRecords() 0 7 2
A create_new() 0 34 5
A debug() 0 4 1

How to fix   Complexity   

Complex Class

Complex classes like EcommerceCurrency often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use EcommerceCurrency, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/**
4
 * Object to manage currencies.
5
 *
6
 * @authors: Nicolaas [at] Sunny Side Up .co.nz
7
 * @package: ecommerce
8
 * @sub-package: money
9
 * Precondition : There should always be at least one currency usable.
10
 **/
11
class EcommerceCurrency extends DataObject implements EditableEcommerceObject
12
{
13
    /**
14
     * standard SS variable.
15
     *
16
     * @var array
17
     */
18
    private static $db = array(
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...
19
        'Code' => 'Varchar(3)',
20
        'Name' => 'Varchar(100)',
21
        'InUse' => 'Boolean',
22
    );
23
24
    /**
25
     * standard SS variable.
26
     *
27
     * @var array
28
     */
29
    private static $indexes = array(
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...
30
        'Code' => true,
31
        'InUse' => true,
32
        'Name' => true
33
    );
34
35
    /**
36
     * standard SS variable.
37
     *
38
     * @var array
39
     */
40
    private static $casting = array(
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...
41
        'IsDefault' => 'Boolean',
42
        'IsDefaultNice' => 'Varchar',
43
        'InUseNice' => 'Varchar',
44
        'ExchangeRate' => 'Double',
45
        'DefaultSymbol' => 'Varchar',
46
        'ShortSymbol' => 'Varchar',
47
        'LongSymbol' => 'Varchar',
48
    );
49
50
    /**
51
     * standard SS variable.
52
     *
53
     * @var array
54
     */
55
    private static $searchable_fields = array(
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...
56
        'Code' => 'PartialMatchFilter',
57
        'Name' => 'PartialMatchFilter',
58
    );
59
60
    /**
61
     * standard SS variable.
62
     *
63
     * @var array
64
     */
65
    private static $field_labels = array(
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...
66
        'Code' => 'Short Code',
67
        'Name' => 'Name',
68
        'InUse' => 'It is available for use?',
69
        'ExchangeRate' => 'Exchange Rate',
70
        'ExchangeRateExplanation' => 'Exchange Rate explanation',
71
        'IsDefaultNice' => 'Is default currency for site',
72
        'DefaultSymbol' => 'Default symbol',
73
        'ShortSymbol' => 'Short symbol',
74
        'LongSymbol' => 'Long symbol',
75
    );
76
77
    /**
78
     * standard SS variable.
79
     *
80
     * @var array
81
     */
82
    private static $summary_fields = array(
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...
83
        'Code' => 'Code',
84
        'Name' => 'Name',
85
        'InUseNice' => 'Available',
86
        'IsDefaultNice' => 'Default Currency',
87
        'ExchangeRate' => 'Exchange Rate',
88
    ); //note no => for relational fields
89
90
    /**
91
     * standard SS variable.
92
     *
93
     * @var string
94
     */
95
    private static $singular_name = 'Currency';
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...
96
    public function i18n_singular_name()
97
    {
98
        return _t('EcommerceCurrency.CURRENCY', 'Currency');
99
    }
100
101
    /**
102
     * standard SS variable.
103
     *
104
     * @var string
105
     */
106
    private static $plural_name = 'Currencies';
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...
107
    public function i18n_plural_name()
108
    {
109
        return _t('EcommerceCurrency.CURRENCIES', 'Currencies');
110
    }
111
112
    /**
113
     * standard SS variable.
114
     *
115
     * @var string
116
     */
117
    private static $default_sort = [
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...
118
        'InUse' => 'DESC',
119
        'Name' => 'ASC',
120
        'Code' => 'ASC',
121
        'ID' => 'DESC'
122
    ];
123
124
    /**
125
     * standard SS variable.
126
     *
127
     * @var array
128
     */
129
    private static $defaults = array(
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...
130
        'InUse' => true
131
    );
132
133
    /**
134
     * Standard SS Method.
135
     *
136
     * @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...
137
     *
138
     * @var bool
139
     */
140
    public function canCreate($member = null)
141
    {
142
        if (! $member) {
143
            $member = Member::currentUser();
144
        }
145
        $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...
146
        if ($extended !== null) {
147
            return $extended;
148
        }
149
        if (Permission::checkMember($member, Config::inst()->get('EcommerceRole', 'admin_permission_code'))) {
150
            return true;
151
        }
152
153
        return parent::canEdit($member);
0 ignored issues
show
Bug introduced by
It seems like $member defined by \Member::currentUser() on line 143 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...
Comprehensibility Bug introduced by
It seems like you call parent on a different method (canEdit() instead of canCreate()). Are you sure this is correct? If so, you might want to change this to $this->canEdit().

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...
154
    }
155
156
    /**
157
     * Standard SS Method.
158
     *
159
     * @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...
160
     *
161
     * @var bool
162
     */
163
    public function canView($member = null)
164
    {
165
        if (! $member) {
166
            $member = Member::currentUser();
167
        }
168
        $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...
169
        if ($extended !== null) {
170
            return $extended;
171
        }
172
        if (Permission::checkMember($member, Config::inst()->get('EcommerceRole', 'admin_permission_code'))) {
173
            return true;
174
        }
175
176
        return parent::canEdit($member);
0 ignored issues
show
Bug introduced by
It seems like $member defined by \Member::currentUser() on line 166 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...
Comprehensibility Bug introduced by
It seems like you call parent on a different method (canEdit() instead of canView()). Are you sure this is correct? If so, you might want to change this to $this->canEdit().

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...
177
    }
178
179
    /**
180
     * Standard SS Method.
181
     *
182
     * @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...
183
     *
184
     * @var bool
185
     */
186
    public function canEdit($member = null)
187
    {
188
        if (! $member) {
189
            $member = Member::currentUser();
190
        }
191
        $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...
192
        if ($extended !== null) {
193
            return $extended;
194
        }
195
        if (Permission::checkMember($member, Config::inst()->get('EcommerceRole', 'admin_permission_code'))) {
196
            return true;
197
        }
198
199
        return parent::canEdit($member);
0 ignored issues
show
Bug introduced by
It seems like $member defined by \Member::currentUser() on line 189 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...
200
    }
201
202
    /**
203
     * Standard SS method.
204
     *
205
     * @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...
206
     *
207
     * @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...
208
     */
209
    public function canDelete($member = null)
210
    {
211
        if (!$this->InUse && EcommerceCurrency::get()->Count() > 1) {
0 ignored issues
show
Documentation introduced by
The property InUse does not exist on object<EcommerceCurrency>. 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...
212
            if (! $member) {
213
                $member = Member::currentUser();
214
            }
215
            $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...
216
            if ($extended !== null) {
217
                return $extended;
218
            }
219
            if (Permission::checkMember($member, Config::inst()->get('EcommerceRole', 'admin_permission_code'))) {
220
                return true;
221
            }
222
223
            return parent::canEdit($member);
0 ignored issues
show
Bug introduced by
It seems like $member defined by \Member::currentUser() on line 213 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...
Comprehensibility Bug introduced by
It seems like you call parent on a different method (canEdit() instead of canDelete()). Are you sure this is correct? If so, you might want to change this to $this->canEdit().

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...
224
        }
225
226
        return false;
227
    }
228
229
    /**
230
     * NOTE: when there is only one currency we return an empty DataList
231
     * as one currency is meaningless.
232
     *
233
     * @return DataList | null
0 ignored issues
show
Documentation introduced by
Should the return type not be DataList|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...
234
     */
235
    public static function ecommerce_currency_list()
236
    {
237
        $dos = EcommerceCurrency::get()
238
            ->Filter(array('InUse' => 1))
239
            ->Sort(
240
                array(
241
                    "IF(\"Code\" = '".strtoupper(EcommerceConfig::get('EcommerceCurrency', 'default_currency'))."', 0, 1)" => 'ASC',
242
                    'Name' => 'ASC',
243
                    'Code' => 'ASC',
244
                )
245
            );
246
        if ($dos->count() < 2) {
247
            return;
248
        }
249
250
        return $dos;
251
    }
252
253
    public static function get_list()
254
    {
255
        return EcommerceCurrency::get()
256
            ->filter(array('InUse' => 1))
257
            ->sort(
258
                array(
259
                    "IF(\"Code\" = '".EcommerceConfig::get('EcommerceCurrency', 'default_currency')."', 0, 1)" => 'ASC',
260
                    'Name' => 'ASC',
261
                    'Code' => 'ASC',
262
                )
263
            );
264
    }
265
266
    /**
267
     * @param float | Currency $price
268
     * @param Order $order
0 ignored issues
show
Documentation introduced by
Should the type for parameter $order not be null|Order?

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...
269
     *
270
     * @return Money
271
     */
272
    public static function get_money_object_from_order_currency($price, Order $order = null)
273
    {
274
        if ($price instanceof Currency) {
275
            $price = $price->getValue();
276
        }
277
        if (!$order) {
278
            $order = ShoppingCart::current_order();
279
        }
280
        $currency = $order->CurrencyUsed();
0 ignored issues
show
Documentation Bug introduced by
The method CurrencyUsed does not exist on object<Order>? 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...
281
        $currencyCode = $currency->Code;
282
        if ($order) {
283
            if ($order->HasAlternativeCurrency()) {
284
                $exchangeRate = $order->ExchangeRate;
0 ignored issues
show
Documentation introduced by
The property ExchangeRate does not exist on object<Order>. 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...
285
                if ($exchangeRate && $exchangeRate != 1) {
286
                    $price = $exchangeRate * $price;
287
                }
288
            }
289
        }
290
291
        $updatedCurrencyCode = Injector::inst()->get('EcommerceCurrency')->extend('updateCurrencyCodeForMoneyObect', $currencyCode);
292
        if ($updatedCurrencyCode !== null && is_array($updatedCurrencyCode) && count($updatedCurrencyCode)) {
293
            $currencyCode = $updatedCurrencyCode[0];
294
        }
295
296
        return DBField::create_field(
297
            'Money',
298
            array(
299
                'Amount' => $price,
300
                'Currency' => $currencyCode
301
            )
302
        );
303
    }
304
305
    /**
306
     * returns the default currency.
307
     */
308
    public static function default_currency()
309
    {
310
        return DataObject::get_one(
311
            'EcommerceCurrency',
312
            array(
313
                'Code' => trim(strtolower(EcommerceConfig::get('EcommerceCurrency', 'default_currency'))),
314
                'InUse' => 1,
315
            )
316
        );
317
    }
318
319
    /**
320
     * returns the default currency as Code.
321
     *
322
     * @return string - e.g. NZD
323
     */
324
    public static function default_currency_code()
325
    {
326
        $obj = self::default_currency();
327
        if ($obj) {
328
            $code = $obj->Code;
329
        }
330
        if (!$code) {
0 ignored issues
show
Bug introduced by
The variable $code does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
331
            $code = EcommerceConfig::get('EcommerceCurrency', 'default_currency');
332
        }
333
        if (!$code) {
334
            $code = 'NZD';
335
        }
336
337
        return strtoupper($code);
338
    }
339
340
    /**
341
     * @return int
342
     */
343
    public static function default_currency_id()
344
    {
345
        $currency = self::default_currency();
346
347
        return $currency ? $currency->ID : 0;
348
    }
349
350
    /**
351
     * Only returns a currency when it is a valid currency.
352
     *
353
     * @param string $currencyCode - the code of the currency, e.g. nzd
354
     *
355
     * @return EcommerceCurrency | Null
356
     */
357
    public static function get_one_from_code($currencyCode)
358
    {
359
        return DataObject::get_one(
360
            'EcommerceCurrency',
361
            array(
362
                'Code' => trim(strtoupper($currencyCode)),
363
                'InUse' => 1,
364
            )
365
        );
366
    }
367
368
    /**
369
     * STANDARD SILVERSTRIPE STUFF.
370
     **/
371
    public function getCMSFields()
372
    {
373
        $fields = parent::getCMSFields();
374
        $fieldLabels = $this->fieldLabels();
375
        $codeField = $fields->dataFieldByName('Code');
376
        $codeField->setRightTitle('e.g. NZD, use uppercase codes');
377
        $titleField = $fields->dataFieldByName('Name');
378
        $titleField->setRightTitle('e.g. New Zealand Dollar');
379
        $fields->addFieldToTab('Root.Main', new ReadonlyField('IsDefaulNice', $fieldLabels['IsDefaultNice'], $this->getIsDefaultNice()));
380
        if (!$this->isDefault()) {
381
            $fields->addFieldToTab('Root.Main', new ReadonlyField('ExchangeRate', $fieldLabels['ExchangeRate'], $this->ExchangeRate()));
382
            $fields->addFieldToTab('Root.Main', new ReadonlyField('ExchangeRateExplanation', $fieldLabels['ExchangeRateExplanation'], $this->ExchangeRateExplanation()));
383
        }
384
        $fields->addFieldsToTab('Root.Main', array(
385
            new HeaderField('Symbols'),
386
            new ReadonlyField('DefaultSymbol', 'Default'),
387
            new ReadonlyField('ShortSymbol', 'Short'),
388
            new ReadonlyField('LongSymbol', 'Long'),
389
        ));
390
391
        return $fields;
392
    }
393
394
    /**
395
     * link to edit the record.
396
     *
397
     * @param string | Null $action - e.g. edit
398
     *
399
     * @return string
0 ignored issues
show
Documentation introduced by
Should the return type not be null|string?

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...
400
     */
401
    public function CMSEditLink($action = null)
402
    {
403
        return CMSEditLinkAPI::find_edit_link_for_object($this, $action);
404
    }
405
406
    public function DefaultSymbol()
407
    {
408
        return $this->getDefaultSymbol();
409
    }
410
    public function getDefaultSymbol()
411
    {
412
        return EcommerceMoney::get_default_symbol($this->Code);
0 ignored issues
show
Documentation introduced by
The property Code does not exist on object<EcommerceCurrency>. 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...
413
    }
414
415
    public function ShortSymbol()
416
    {
417
        return $this->getShortSymbol();
418
    }
419
    public function getShortSymbol()
420
    {
421
        return EcommerceMoney::get_short_symbol($this->Code);
0 ignored issues
show
Documentation introduced by
The property Code does not exist on object<EcommerceCurrency>. 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...
422
    }
423
424
    public function LongSymbol()
425
    {
426
        return $this->getLongSymbol();
427
    }
428
    public function getLongSymbol()
429
    {
430
        return EcommerceMoney::get_long_symbol($this->Code);
0 ignored issues
show
Documentation introduced by
The property Code does not exist on object<EcommerceCurrency>. 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...
431
    }
432
433
    /**
434
     * casted variable method.
435
     *
436
     * @return bool
437
     */
438
    public function IsDefault()
439
    {
440
        return $this->getIsDefault();
441
    }
442
    public function getIsDefault()
443
    {
444
        $outcome = false;
0 ignored issues
show
Unused Code introduced by
$outcome is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
445
        if ($this->exists()) {
446
            if (!$this->Code) {
0 ignored issues
show
Documentation introduced by
The property Code does not exist on object<EcommerceCurrency>. 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...
447
                user_error('This currency (ID = '.$this->ID.') does not have a code ');
448
            }
449
        }
450
451
        return strtoupper($this->Code) ==  strtoupper(EcommerceConfig::get('EcommerceCurrency', 'default_currency'));
0 ignored issues
show
Documentation introduced by
The property Code does not exist on object<EcommerceCurrency>. 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...
452
    }
453
454
    /**
455
     * casted variable method.
456
     *
457
     * @return string
458
     */
459
    public function IsDefaultNice()
460
    {
461
        return $this->getIsDefaultNice();
462
    }
463
    public function getIsDefaultNice()
464
    {
465
        if ($this->getIsDefault()) {
466
            return _t('EcommerceCurrency.YES', 'Yes');
467
        } else {
468
            return _t('EcommerceCurrency.NO', 'No');
469
        }
470
    }
471
472
    /**
473
     * casted variable method.
474
     *
475
     * @return string
476
     */
477
    public function InUseNice()
478
    {
479
        return $this->getInUseNice();
480
    }
481
    public function getInUseNice()
482
    {
483
        if ($this->InUse) {
0 ignored issues
show
Documentation introduced by
The property InUse does not exist on object<EcommerceCurrency>. 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...
484
            return _t('EcommerceCurrency.YES', 'Yes');
485
        } else {
486
            return _t('EcommerceCurrency.NO', 'No');
487
        }
488
    }
489
490
    /**
491
     * casted variable.
492
     * @alias for getExchangeRate
493
     *
494
     * @return float
495
     */
496
    public function ExchangeRate()
497
    {
498
        return $this->getExchangeRate();
499
    }
500
501
    /**
502
     *
503
     * @return float
504
     */
505
    public function getExchangeRate()
506
    {
507
        $exchangeRateProviderClassName = EcommerceConfig::get('EcommerceCurrency', 'exchange_provider_class');
508
        $exchangeRateProvider = new $exchangeRateProviderClassName();
509
510
        return $exchangeRateProvider->ExchangeRate(EcommerceConfig::get('EcommerceCurrency', 'default_currency'), $this->Code);
0 ignored issues
show
Documentation introduced by
The property Code does not exist on object<EcommerceCurrency>. 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...
511
    }
512
513
    /**
514
     * casted variable.
515
     *
516
     * @return string
0 ignored issues
show
Documentation introduced by
Should the return type not be 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...
517
     */
518
    public function ExchangeRateExplanation()
519
    {
520
        return $this->getExchangeRateExplanation();
521
    }
522
523
    /**
524
     *
525
     *
526
     * @return string
0 ignored issues
show
Documentation introduced by
Should the return type not be 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...
527
     */
528
    public function getExchangeRateExplanation()
529
    {
530
        $string = '1 '.EcommerceConfig::get('EcommerceCurrency', 'default_currency').' = '.round($this->getExchangeRate(), 3).' '.$this->Code;
0 ignored issues
show
Documentation introduced by
The property Code does not exist on object<EcommerceCurrency>. 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...
531
        $exchangeRate = $this->getExchangeRate();
532
        $exchangeRateError = '';
533
        if (!$exchangeRate) {
534
            $exchangeRate = 1;
535
            $exchangeRateError = _t('EcommerceCurrency.EXCHANGE_RATE_ERROR', 'Error in exchange rate. ');
536
        }
537
        $string .= ', 1 '.$this->Code.' = '.round(1 / $exchangeRate, 3).' '.EcommerceConfig::get('EcommerceCurrency', 'default_currency').'. '.$exchangeRateError;
0 ignored issues
show
Documentation introduced by
The property Code does not exist on object<EcommerceCurrency>. 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...
538
    }
539
540
    /**
541
     * @return bool
542
     */
543
    public function IsCurrent()
544
    {
545
        $order = ShoppingCart::current_order();
546
547
        return $order ? $order->CurrencyUsedID == $this->ID : false;
0 ignored issues
show
Documentation introduced by
The property CurrencyUsedID does not exist on object<Order>. 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...
548
    }
549
550
    /**
551
     * Returns the link that can be used in the shopping cart to
552
     * set the preferred currency to this one.
553
     * For example: /shoppingcart/setcurrency/nzd/
554
     * Dont be fooled by the set_ part in the set_currency_link....
555
     *
556
     * @return string
557
     */
558
    public function Link()
559
    {
560
        return ShoppingCart_Controller::set_currency_link($this->Code);
0 ignored issues
show
Documentation introduced by
The property Code does not exist on object<EcommerceCurrency>. 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...
561
    }
562
563
    /**
564
     * returns the link type.
565
     *
566
     * @return string (link | default | current)
567
     */
568
    public function LinkingMode()
569
    {
570
        $linkingMode = '';
571
        if ($this->IsDefault()) {
572
            $linkingMode .= ' default';
573
        }
574
        if ($this->IsCurrent()) {
575
            $linkingMode .= ' current';
576
        } else {
577
            $linkingMode .= ' link';
578
        }
579
580
        return $linkingMode;
581
    }
582
583
    public function validate()
584
    {
585
        $result = parent::validate();
586
        $errors = array();
587
        if (!$this->Code || mb_strlen($this->Code) != 3) {
0 ignored issues
show
Documentation introduced by
The property Code does not exist on object<EcommerceCurrency>. 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...
588
            $errors[] = 'The code must be 3 characters long.';
589
        }
590
        if (!$this->Name) {
0 ignored issues
show
Documentation introduced by
The property Name does not exist on object<EcommerceCurrency>. 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...
591
            $errors[] = 'The name is required.';
592
        }
593
        if (!count($errors)) {
594
            $this->Code = strtoupper($this->Code);
0 ignored issues
show
Documentation introduced by
The property Code does not exist on object<EcommerceCurrency>. 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...
Documentation introduced by
The property Code does not exist on object<EcommerceCurrency>. 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...
595
            // Check that there are no 2 same code currencies in use
596
            if ($this->isChanged('Code')) {
597
                if (EcommerceCurrency::get()->where("UPPER(\"Code\") = '".$this->Code."'")->exclude('ID', intval($this->ID) - 0)->count()) {
0 ignored issues
show
Documentation introduced by
The property Code does not exist on object<EcommerceCurrency>. 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...
598
                    $errors[] = "There is alreay another currency in use which code is '$this->Code'.";
0 ignored issues
show
Documentation introduced by
The property Code does not exist on object<EcommerceCurrency>. 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...
599
                }
600
            }
601
        }
602
        foreach ($errors as $error) {
603
            $result->error($error);
604
        }
605
606
        return $result;
607
    }
608
609
    /**
610
     * Standard SS Method
611
     * Adds the default currency.
612
     */
613
    public function populateDefaults()
614
    {
615
        parent::populateDefaults();
616
        $this->InUse = true;
0 ignored issues
show
Documentation introduced by
The property InUse does not exist on object<EcommerceCurrency>. 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...
617
    }
618
619
    public function onBeforeWrite()
620
    {
621
        parent::onBeforeWrite();
622
        // Check that there is always at least one currency in use
623
        $this->Code = strtoupper($this->Code);
0 ignored issues
show
Documentation introduced by
The property Code does not exist on object<EcommerceCurrency>. 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...
Documentation introduced by
The property Code does not exist on object<EcommerceCurrency>. 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...
624
        if (!$this->InUse) {
0 ignored issues
show
Documentation introduced by
The property InUse does not exist on object<EcommerceCurrency>. 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...
625
            $list = self::get_list();
626
            if ($list->count() == 0 || ($list->Count() == 1 && $list->First()->ID == $this->ID)) {
627
                $this->InUse = true;
0 ignored issues
show
Documentation introduced by
The property InUse does not exist on object<EcommerceCurrency>. 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...
628
            }
629
        }
630
    }
631
632
    /**
633
     * Standard SS Method
634
     * Adds the default currency.
635
     */
636
    public function requireDefaultRecords()
637
    {
638
        parent::requireDefaultRecords();
639
        if (! self::default_currency()) {
640
            self::create_new(EcommerceConfig::get('EcommerceCurrency', 'default_currency'));
641
        }
642
    }
643
644
    /**
645
     * checks if a currency exists, creates it and returns it.
646
     *
647
     * @param string $code
648
     * @param string $name OPTIONAL
649
     */
650
    public static function create_new($code, $name = '')
651
    {
652
        $code = trim(strtoupper($code));
653
        if (!$name) {
654
            $currencies = Config::inst()->get('EcommerceCurrency', 'currencies');
655
            if (isset($currencies[$code])) {
656
                $name = $currencies[$code];
657
            } else {
658
                $name = $code;
659
            }
660
        }
661
        $name = ucwords($name);
662
        $currency = DataObject::get_one(
663
            'EcommerceCurrency',
664
            array('Code' => $code),
665
            $cacheDataObjectGetOne = false
666
        );
667
        if ($currency) {
668
            $currency->Name = $name;
669
            $currency->InUse = true;
670
        } else {
671
            $currency = EcommerceCurrency::create(
672
                array(
673
                'Code' => $code,
674
                'Name' => $name,
675
                'InUse' => true,
676
                )
677
            );
678
        }
679
        $valid = $currency->write();
680
        if ($valid) {
681
            return $currency;
682
        }
683
    }
684
685
    /**
686
     * Debug helper method.
687
     * Can be called from /shoppingcart/debug/.
688
     *
689
     * @return string
690
     */
691
    public function debug()
692
    {
693
        return EcommerceTaskDebugCart::debug_object($this);
694
    }
695
696
    private static $currencies = array(
697
        'AFA' => 'afghanistan afghanis',
698
        'ALL' => 'albania leke',
699
        'DZD' => 'algeria dinars',
700
        'ARS' => 'argentina pesos',
701
        'AUD' => 'australia dollars',
702
        'ATS' => 'austria schillings*',
703
        'BSD' => 'bahamas dollars',
704
        'BHD' => 'bahrain dinars',
705
        'BDT' => 'bangladesh taka',
706
        'BBD' => 'barbados dollars',
707
        'BEF' => 'belgium francs*',
708
        'BMD' => 'bermuda dollars',
709
        'BRL' => 'brazil reais',
710
        'BGN' => 'bulgaria leva',
711
        'CAD' => 'canada dollars',
712
        'XOF' => 'cfa bceao francs',
713
        'XAF' => 'cfa beac francs',
714
        'CLP' => 'chile pesos',
715
        'CNY' => 'china yuan renminbi',
716
        'COP' => 'colombia pesos',
717
        'CRC' => 'costa rica colones',
718
        'HRK' => 'croatia kuna',
719
        'CYP' => 'cyprus pounds',
720
        'CZK' => 'czech republic koruny',
721
        'DKK' => 'denmark kroner',
722
        'DOP' => 'dominican republic pesos',
723
        'XCD' => 'eastern caribbean dollars',
724
        'EGP' => 'egypt pounds',
725
        'EEK' => 'estonia krooni',
726
        'EUR' => 'euro',
727
        'FJD' => 'fiji dollars',
728
        'DEM' => 'germany deutsche marks*',
729
        'XAU' => 'gold ounces',
730
        'NLG' => 'holland (netherlands) guilders*',
731
        'HKD' => 'hong kong dollars',
732
        'HUF' => 'hungary forint',
733
        'ISK' => 'iceland kronur',
734
        'XDR' => 'imf special drawing right',
735
        'INR' => 'india rupees',
736
        'IDR' => 'indonesia rupiahs',
737
        'IRR' => 'iran rials',
738
        'IQD' => 'iraq dinars',
739
        'ILS' => 'israel new shekels',
740
        'JMD' => 'jamaica dollars',
741
        'JPY' => 'japan yen',
742
        'JOD' => 'jordan dinars',
743
        'KES' => 'kenya shillings',
744
        'KRW' => 'korea (south) won',
745
        'KWD' => 'kuwait dinars',
746
        'LBP' => 'lebanon pounds',
747
        'MYR' => 'malaysia ringgits',
748
        'MTL' => 'malta liri',
749
        'MUR' => 'mauritius rupees',
750
        'MXN' => 'mexico pesos',
751
        'MAD' => 'morocco dirhams',
752
        'NZD' => 'new zealand dollars',
753
        'NOK' => 'norway kroner',
754
        'OMR' => 'oman rials',
755
        'PKR' => 'pakistan rupees',
756
        'XPD' => 'palladium ounces',
757
        'PEN' => 'peru nuevos soles',
758
        'PHP' => 'philippines pesos',
759
        'PLN' => 'poland zlotych',
760
        'QAR' => 'qatar riyals',
761
        'ROL' => 'romania lei',
762
        'RUB' => 'russia rubles',
763
        'SAR' => 'saudi arabia riyals',
764
        'XAG' => 'silver ounces',
765
        'SGD' => 'singapore dollars',
766
        'SKK' => 'slovakia koruny',
767
        'SIT' => 'slovenia tolars',
768
        'ZAR' => 'south africa rand',
769
        'KRW' => 'south korea won',
770
        'LKR' => 'sri lanka rupees',
771
        'SDD' => 'sudan dinars',
772
        'SEK' => 'sweden kronor',
773
        'CHF' => 'switzerland francs',
774
        'TWD' => 'taiwan new dollars',
775
        'THB' => 'thailand baht',
776
        'TTD' => 'trinidad and tobago dollars',
777
        'TND' => 'tunisia dinars',
778
        'TRY' => 'turkey new lira',
779
        'AED' => 'united arab emirates dirhams',
780
        'gbp' => 'united kingdom pounds',
781
        'USD' => 'united states dollars',
782
        'VEB' => 'venezuela bolivares',
783
        'VND' => 'vietnam dong',
784
        'ZMK' => 'zambia kwacha',
785
    );
786
}
787