Issues (2002)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

code/model/config/EcommerceDBConfig.php (47 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
/**
4
 * Database Settings for E-commerce
5
 * Similar to SiteConfig but then for E-commerce
6
 * To access a singleton here, use: EcommerceDBConfig::current_ecommerce_db_config().
7
 *
8
 * @authors: Nicolaas [at] Sunny Side Up .co.nz
9
 * @package: ecommerce
10
 * @sub-package: tasks
11
 * @inspiration: Silverstripe Ltd, Jeremy
12
 **/
13
class EcommerceDBConfig extends DataObject implements EditableEcommerceObject
14
{
15
    /**
16
     * Standard SS Variable.
17
     *
18
     * @var array
19
     */
20
    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...
21
        'Title' => 'Varchar(30)',
22
        'UseThisOne' => 'Boolean',
23
        'ShopClosed' => 'Boolean',
24
        'ShopPricesAreTaxExclusive' => 'Boolean',
25
        'InvoiceTitle' => 'Varchar(200)',
26
        'InvoiceMessage' => 'HTMLText',
27
        'PackingSlipTitle' => 'Varchar(200)',
28
        'PackingSlipNote' => 'HTMLText',
29
        'ShopPhysicalAddress' => 'HTMLText',
30
        'ReceiptEmail' => 'Varchar(255)',
31
        'PostalCodeURL' => 'Varchar(255)',
32
        'PostalCodeLabel' => 'Varchar(255)',
33
        'NumberOfProductsPerPage' => 'Int',
34
        'ProductsAlsoInOtherGroups' => 'Boolean',
35
        'OnlyShowProductsThatCanBePurchased' => 'Boolean',
36
        'NotForSaleMessage' => 'HTMLText',
37
        'ProductsHaveWeight' => 'Boolean',
38
        'ProductsHaveModelNames' => 'Boolean',
39
        'ProductsHaveQuantifiers' => 'Boolean',
40
        //"ProductsHaveVariations" => "Boolean",
41
        'CurrenciesExplanation' => 'HTMLText',
42
        'AllowFreeProductPurchase' => 'Boolean',
43
    );
44
45
    /**
46
     * Standard SS Variable.
47
     *
48
     * @var array
49
     */
50
    private static $has_one = 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...
51
        'EmailLogo' => 'Image',
52
        'DefaultProductImage' => 'Product_Image',
53
    );
54
55
    /**
56
     * Standard SS Variable.
57
     *
58
     * @var array
59
     */
60
    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...
61
        'UseThisOne' => true,
62
        'ShopClosed' => true,
63
        'ShopPricesAreTaxExclusive' => true,
64
        'NumberOfProductsPerPage' => true,
65
        'OnlyShowProductsThatCanBePurchased' => true,
66
    );
67
68
    /**
69
     * Standard SS Variable.
70
     *
71
     * @var array
72
     */
73
    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...
74
        'UseThisOneNice' => 'Varchar',
75
    ); //adds computed fields that can also have a type (e.g.
76
77
    /**
78
     * Standard SS Variable.
79
     *
80
     * @var array
81
     */
82
    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...
83
        'Title' => 'PartialMatchFilter',
84
    );
85
86
    /**
87
     * Standard SS Variable.
88
     *
89
     * @var array
90
     */
91
    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...
92
93
    /**
94
     * Standard SS Variable.
95
     *
96
     * @var array
97
     */
98
    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...
99
        'Title' => 'Title',
100
        'UseThisOneNice' => 'Use this configuration set',
101
    ); //note no => for relational fields
102
103
    /**
104
     * Standard SS Method.
105
     *
106
     * @param Member $member
0 ignored issues
show
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...
107
     *
108
     * @var bool
109
     */
110
    public function canCreate($member = null)
111
    {
112
        if (! $member) {
113
            $member = Member::currentUser();
114
        }
115
        $extended = $this->extendedCan(__FUNCTION__, $member);
0 ignored issues
show
$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...
116
        if ($extended !== null) {
117
            return $extended;
118
        }
119
        if (EcommerceDBConfig::get()->count() > 0) {
120
            return false;
121
        }
122
        return $this->canEdit($member);
0 ignored issues
show
It seems like $member defined by \Member::currentUser() on line 113 can also be of type object<DataObject>; however, EcommerceDBConfig::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...
123
    }
124
125
    /**
126
     * Standard SS Method.
127
     *
128
     * @param Member $member
0 ignored issues
show
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...
129
     *
130
     * @var bool
131
     */
132
    public function canView($member = null)
133
    {
134
        if (! $member) {
135
            $member = Member::currentUser();
136
        }
137
        $extended = $this->extendedCan(__FUNCTION__, $member);
0 ignored issues
show
$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...
138
        if ($extended !== null) {
139
            return $extended;
140
        }
141
142
        return $this->canEdit($member);
0 ignored issues
show
It seems like $member defined by \Member::currentUser() on line 135 can also be of type object<DataObject>; however, EcommerceDBConfig::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...
143
    }
144
145
    /**
146
     * Standard SS Method.
147
     *
148
     * @param Member $member
0 ignored issues
show
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...
149
     *
150
     * @var bool
151
     */
152
    public function canEdit($member = null)
153
    {
154
        if (! $member) {
155
            $member = Member::currentUser();
156
        }
157
        $extended = $this->extendedCan(__FUNCTION__, $member);
0 ignored issues
show
$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...
158
        if ($extended !== null) {
159
            return $extended;
160
        }
161
        if (Permission::checkMember($member, Config::inst()->get('EcommerceRole', 'admin_permission_code'))) {
162
            return true;
163
        }
164
165
        return parent::canEdit($member);
0 ignored issues
show
It seems like $member defined by \Member::currentUser() on line 155 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...
166
    }
167
168
    /**
169
     * Standard SS Method.
170
     *
171
     * @param Member $member
0 ignored issues
show
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...
172
     *
173
     * @var bool
174
     */
175
    public function canDelete($member = null)
176
    {
177
        if ($this->UseThisOne) {
0 ignored issues
show
The property UseThisOne does not exist on object<EcommerceDBConfig>. 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...
178
            return false;
179
        } else {
180
            if (! $member) {
181
                $member = Member::currentUser();
182
            }
183
            $extended = $this->extendedCan(__FUNCTION__, $member);
0 ignored issues
show
$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...
184
            if ($extended !== null) {
185
                return $extended;
186
            }
187
            if (Permission::checkMember($member, Config::inst()->get('EcommerceRole', 'admin_permission_code'))) {
188
                return true;
189
            }
190
191
            return parent::canEdit($member);
0 ignored issues
show
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...
It seems like $member defined by \Member::currentUser() on line 181 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...
192
        }
193
    }
194
195
    /**
196
     * Standard SS variable.
197
     *
198
     * @var string
199
     */
200
    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...
201
        'UseThisOne' => 'DESC',
202
        'ID' => 'ASC'
203
    ];
204
205
    /**
206
     * Standard SS variable.
207
     *
208
     * @var array
209
     */
210
    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...
211
        'Title' => 'Ecommerce Site Config',
212
        'UseThisOne' => true,
213
        'ShopClosed' => false,
214
        'ShopPricesAreTaxExclusive' => false,
215
        'InvoiceTitle' => 'Invoice',
216
        'InvoiceMessage' => '<p>Thank you for your order</p>',
217
        'PackingSlipTitle' => 'Package Contents',
218
        'PackingSlipNote' => 'Please make sure that all items are contained in this package.',
219
        'ShopPhysicalAddress' => '<p>Enter your shop address here.</p>',
220
        //"ReceiptEmail" => "Varchar(255)", - see populate defaults
221
        'PostalCodeURL' => '',
222
        'PostalCodeLabel' => '',
223
        'NumberOfProductsPerPage' => 12,
224
        'ProductsAlsoInOtherGroups' => false,
225
        'OnlyShowProductsThatCanBePurchased' => false,
226
        'NotForSaleMessage' => '<p>Not for sale, please contact us for more information.</p>',
227
        'ProductsHaveWeight' => false,
228
        'ProductsHaveModelNames' => false,
229
        'ProductsHaveQuantifiers' => false,
230
        //"ProductsHaveVariations" => false,
231
        'CurrenciesExplanation' => '<p>Apart from our main currency, you can view prices in a number of other currencies. The exchange rate is indicative only.</p>',
232
        'AllowFreeProductPurchase' => true,
233
    );
234
235
    /**
236
     * Standard SS Method.
237
     *
238
     * @var array
239
     */
240
    public function populateDefaults()
241
    {
242
        parent::populateDefaults();
243
        $this->ReceiptEmail = Email::config()->admin_email;
0 ignored issues
show
The property ReceiptEmail does not exist on object<EcommerceDBConfig>. 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...
244
    }
245
246
    /**
247
     * Standard SS variable.
248
     *
249
     * @var string
250
     */
251
    private static $singular_name = 'Main E-commerce Configuration';
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...
252
    public function i18n_singular_name()
253
    {
254
        return _t('EcommerceDBConfig.ECOMMERCECONFIGURATION', 'Main E-commerce Configuration');
255
    }
256
257
    /**
258
     * Standard SS variable.
259
     *
260
     * @var string
261
     */
262
    private static $plural_name = 'Main E-commerce Configurations';
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...
263
    public function i18n_plural_name()
264
    {
265
        return _t('EcommerceDBConfig.ECOMMERCECONFIGURATIONS', 'Main E-commerce Configurations');
266
    }
267
268
    /**
269
     * Standard SS variable.
270
     *
271
     * @var string
272
     */
273
    private static $description = 'A set of configurations for the shop. Each shop needs to have one or more of these settings.';
274
275
    /**
276
     * static holder for its own (or other EcommerceDBConfig) class.
277
     *
278
     * @var string | NULL
279
     */
280
    private static $_my_current_one = null;
281
    public static function reset_my_current_one()
282
    {
283
        self::$_my_current_one = null;
284
    }
285
286
    /**
287
     * implements singleton pattern.
288
     * Gets the current USE THIS ONE e-commerce option.
289
     *
290
     * @return EcommerceDBConfig | Object
291
     */
292
    public static function current_ecommerce_db_config()
293
    {
294
        if (!self::$_my_current_one) {
295
            $className = EcommerceConfig::get('EcommerceDBConfig', 'ecommerce_db_config_class_name');
296
            if (!class_exists('EcommerceDBConfig')) {
297
                $class = 'EcommerceDBConfig';
0 ignored issues
show
$class 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...
298
            }
299
            self::$_my_current_one = DataObject::get_one(
0 ignored issues
show
Documentation Bug introduced by
It seems like \DataObject::get_one($cl...taObjectGetOne = false) of type object<DataObject> is incompatible with the declared type string of property $_my_current_one.

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

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

Loading history...
300
                $className,
301
                array('UseThisOne' => 1),
302
                $cacheDataObjectGetOne = false
303
            );
304
            if (! self::$_my_current_one) {
305
                self::$_my_current_one = $className::create();
306
            }
307
        }
308
309
        return self::$_my_current_one;
310
    }
311
312
    /**
313
     * standard SS method for decorators.
314
     *
315
     * @param bool $includerelations
316
     *
317
     * @return array
318
     */
319
    public function fieldLabels($includerelations = true)
320
    {
321
        $defaultLabels = parent::fieldLabels();
322
        $newLabels = $this->customFieldLabels();
323
        $labels = array_merge($defaultLabels, $newLabels);
324
        $extendedLabels = $this->extend('updateFieldLabels', $labels);
325
        if ($extendedLabels !== null && is_array($extendedLabels) && count($extendedLabels)) {
326
            foreach ($extendedLabels as $extendedLabelsUpdate) {
327
                $labels = array_merge($labels, $extendedLabelsUpdate);
328
            }
329
        }
330
331
        return $labels;
332
    }
333
334
    /**
335
     * definition of field lables
336
     * TODO: is this a common SS method?
337
     *
338
     * @return array
339
     */
340
    public function customFieldLabels()
341
    {
342
        $newLabels = array(
343
            'Title' => _t('EcommerceDBConfig.TITLE', 'Name of settings'),
344
            'UseThisOne' => _t('EcommerceDBConfig.USETHISONE', 'Use these configuration settings'),
345
            'ShopClosed' => _t('EcommerceDBConfig.SHOPCLOSED', 'Shop Closed'),
346
            'ShopPricesAreTaxExclusive' => _t('EcommerceDBConfig.SHOPPRICESARETAXEXCLUSIVE', 'Shop prices are tax exclusive'),
347
            'InvoiceTitle' => _t('EcommerceDBConfig.INVOICETITLE', 'Default Email title'),
348
            'InvoiceMessage' => _t('EcommerceDBConfig.INVOICEMESSAGE', 'Default Email Message'),
349
            'PackingSlipTitle' => _t('EcommerceDBConfig.PACKING_SLIP_TITLE', 'Packing slip title'),
350
            'PackingSlipNote' => _t('EcommerceDBConfig.PACKING_SLIP_NOTE', 'Packing slip notes'),
351
            'ShopPhysicalAddress' => _t('EcommerceDBConfig.SHOPPHYSICALADDRESS', 'Shop physical address'),
352
            'ReceiptEmail' => _t('EcommerceDBConfig.RECEIPTEMAIL', 'Shop Email Address'),
353
            'PostalCodeURL' => _t('EcommerceDBConfig.POSTALCODEURL', 'Postal code link'),
354
            'PostalCodeLabel' => _t('EcommerceDBConfig.POSTALCODELABEL', 'Postal code link label'),
355
            'NumberOfProductsPerPage' => _t('EcommerceDBConfig.NUMBEROFPRODUCTSPERPAGE', 'Number of products per page'),
356
            'OnlyShowProductsThatCanBePurchased' => _t('EcommerceDBConfig.ONLYSHOWPRODUCTSTHATCANBEPURCHASED', 'Only show products that can be purchased.'),
357
            'NotForSaleMessage' => _t('EcommerceDBConfig.NOTFORSALEMESSAGE', 'Not for sale message'),
358
            'ProductsHaveWeight' => _t('EcommerceDBConfig.PRODUCTSHAVEWEIGHT', 'Products have weight (e.g. 1.2kg)'),
359
            'ProductsHaveModelNames' => _t('EcommerceDBConfig.PRODUCTSHAVEMODELNAMES', 'Products have model names / numbers / codes'),
360
            'ProductsHaveQuantifiers' => _t('EcommerceDBConfig.PRODUCTSHAVEQUANTIFIERS', 'Products have quantifiers (e.g. per year, each, per dozen, etc...)'),
361
            'ProductsAlsoInOtherGroups' => _t('EcommerceDBConfig.PRODUCTSALSOINOTHERGROUPS', 'Allow products to show in multiple product groups'),
362
            //"ProductsHaveVariations" => _t("EcommerceDBConfig.PRODUCTSHAVEVARIATIONS", "Products have variations (e.g. size, colour, etc...)."),
363
            'CurrenciesExplanation' => _t('EcommerceDBConfig.CURRENCIESEXPLANATION', 'Currency explanation'),
364
            'EmailLogo' => _t('EcommerceDBConfig.EMAILLOGO', 'Email Logo'),
365
            'DefaultProductImage' => _t('EcommerceDBConfig.DEFAULTPRODUCTIMAGE', 'Default Product Image'),
366
            'DefaultThumbnailImageSize' => _t('EcommerceDBConfig.DEFAULTTHUMBNAILIMAGESIZE', 'Product Thumbnail Optimised Size'),
367
            'DefaultSmallImageSize' => _t('EcommerceDBConfig.DEFAULTSMALLIMAGESIZE', 'Product Small Image Optimised Size'),
368
            'DefaultContentImageSize' => _t('EcommerceDBConfig.DEFAULTCONTENTIMAGESIZE', 'Product Content Image Optimised Size'),
369
            'DefaultLargeImageSize' => _t('EcommerceDBConfig.DEFAULTLARGEIMAGESIZE', 'Product Large Image Optimised Size'),
370
            'AllowFreeProductPurchase' => _t('EcommerceDBConfig.ALLOWFREEPRODUCTPURCHASE', 'Allow free products to be purchased? '),
371
        );
372
373
        return $newLabels;
374
    }
375
376
    /**
377
     * definition of field lables
378
     * TODO: is this a common SS method?
379
     *
380
     * @return array
381
     */
382
    public function customDescriptionsForFields()
383
    {
384
        $newLabels = array(
385
            'Title' => _t('EcommerceDBConfig.TITLE_DESCRIPTION', 'For internal use only.'),
386
            'UseThisOne' => _t('EcommerceDBConfig.USETHISONE_DESCRIPTION', 'You can create several setting records so that you can switch between configurations.'),
387
            'ShopPricesAreTaxExclusive' => _t('EcommerceDBConfig.SHOPPRICESARETAXEXCLUSIVE_DESCRIPTION', 'If this option is NOT ticked, it is assumed that prices are tax inclusive.'),
388
            'ReceiptEmail' => _t('EcommerceDBConfig.RECEIPTEMAIL_DESCRIPTION_DESCRIPTION', 'e.g. [email protected], you can also use something like: "Our Shop Name Goes Here" &lt;[email protected]&gt;'),
389
            'AllowFreeProductPurchase' => _t('EcommerceDBConfig.ALLOWFREEPRODUCTPURCHASE_DESCRIPTION', 'This is basically a protection to disallow sales of products that do not have a price entered yet. '),
390
            'CurrenciesExplanation' => _t('EcommerceDBConfig.CURRENCIESEXPLANATION_DESCRIPTION', 'Explain how the user can switch between currencies and how the exchange rates are worked out.'),
391
            'PackingSlipTitle' => _t('EcommerceDBConfig.PACKINGSLIPTITLE_DESCRIPTION', 'e.g. Package Contents'),
392
            'PackingSlipNote' => _t('EcommerceDBConfig.PACKING_SLIP_NOTE_DESCRIPTION', 'e.g. a disclaimer'),
393
            'InvoiceTitle' => _t('EcommerceDBConfig.INVOICETITLE_DESCRIPTION', 'e.g. Tax Invoice or Update for your recent order on www.yoursite.co.nz'),
394
            'InvoiceMessage' => _t('EcommerceDBConfig.INVOICEMESSAGE_DESCRIPTION', 'e.g. Thank you for your order.'),
395
        );
396
397
        return $newLabels;
398
    }
399
400
    /**
401
     * standard SS method.
402
     *
403
     * @return FieldList
404
     */
405
    public function getCMSFields()
406
    {
407
        $fields = parent::getCMSFields();
0 ignored issues
show
$fields 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...
408
409
        $self = $this;
410
        $self->beforeUpdateCMSFields(
411
            function ($fields) use ($self) {
412
                foreach ($self->customFieldLabels() as $name => $label) {
413
                    $fields->removeByName($name);
414
                }
415
                //new section
416
                $fieldDescriptions = $self->customDescriptionsForFields();
417
                $fieldLabels = $self->fieldLabels();
418
                $productImage = new Product_Image();
419
                $versionInfo = EcommerceConfigDefinitions::create();
0 ignored issues
show
$versionInfo 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...
420
                $fields->addFieldToTab('Root.Main', new TextField('Title', $fieldLabels['Title']));
421
                $fields->InsertAfter(
422
                    'Root.Main',
423
                    LiteralField::create(
424
                        'RefreshWebsite',
425
                        '<h2><a href="/shoppingcart/clear/?flush=all">Refresh website, clear caches, and your cart</a></h2>'
426
                    ),
427
                    'Root.Main.ShopClosed'
428
                );
429
                $fields->addFieldsToTab('Root', array(
430
                    Tab::create(
431
                        'Pricing',
432
                        _t('EcommerceDBConfig.PRICING', 'Pricing'),
433
                        new CheckboxField('ShopPricesAreTaxExclusive', $fieldLabels['ShopPricesAreTaxExclusive']),
434
                        new CheckboxField('AllowFreeProductPurchase', $fieldLabels['AllowFreeProductPurchase']),
435
                        $htmlEditorField1 = new HTMLEditorField('CurrenciesExplanation', $fieldLabels['CurrenciesExplanation'])
436
                    ),
437
                    Tab::create(
438
                        'Products',
439
                        _t('EcommerceDBConfig.PRODUCTS', 'Products'),
440
                        new NumericField('NumberOfProductsPerPage', $fieldLabels['NumberOfProductsPerPage']),
441
                        new CheckboxField('ProductsAlsoInOtherGroups', $fieldLabels['ProductsAlsoInOtherGroups']),
442
                        new CheckboxField('OnlyShowProductsThatCanBePurchased', $fieldLabels['OnlyShowProductsThatCanBePurchased']),
443
                        $htmlEditorField2 = new HTMLEditorField('NotForSaleMessage', $fieldLabels['NotForSaleMessage']),
444
                        new CheckboxField('ProductsHaveWeight', $fieldLabels['ProductsHaveWeight']),
445
                        new CheckboxField('ProductsHaveModelNames', $fieldLabels['ProductsHaveModelNames']),
446
                        new CheckboxField('ProductsHaveQuantifiers', $fieldLabels['ProductsHaveQuantifiers'])
447
                        //new CheckboxField("ProductsHaveVariations", $fieldLabels["ProductsHaveVariations"])
448
                    ),
449
                    Tab::create(
450
                        'ProductImages',
451
                        _t('EcommerceDBConfig.PRODUCT_IMAGES', 'Product Images'),
452
                        //new Product_ProductImageUploadField("DefaultProductImage", $fieldLabels["DefaultProductImage"], null, null, null, "default-product-image"),
453
                        new ReadonlyField('DefaultThumbnailImageSize', $fieldLabels['DefaultThumbnailImageSize'], $productImage->ThumbWidth().'px x '.$productImage->ThumbHeight().'px '),
454
                        new ReadonlyField('DefaultSmallImageSize', $fieldLabels['DefaultSmallImageSize'], $productImage->SmallWidth().'px x '.$productImage->SmallHeight().'px '),
455
                        new ReadonlyField('DefaultContentImageSize', $fieldLabels['DefaultContentImageSize'], $productImage->ContentWidth().'px wide'),
456
                        new ReadonlyField('DefaultLargeImageSize', $fieldLabels['DefaultLargeImageSize'], $productImage->LargeWidth().'px wide')
457
                    ),
458
                    Tab::create(
459
                        'AddressAndDelivery',
460
                        _t('EcommerceDBConfig.ADDRESS_AND_DELIVERY', 'Address and Delivery'),
461
                        new TextField('PostalCodeURL', $fieldLabels['PostalCodeURL']),
462
                        new TextField('PostalCodeLabel', $fieldLabels['PostalCodeLabel']),
463
                        $htmlEditorField3 = new HTMLEditorField('ShopPhysicalAddress', $fieldLabels['ShopPhysicalAddress']),
464
                        new TextField('PackingSlipTitle', $fieldLabels['PackingSlipTitle']),
465
                        $htmlEditorField4 = new HTMLEditorField('PackingSlipNote', $fieldLabels['PackingSlipNote'])
466
                    ),
467
                    Tab::create(
468
                        'Emails',
469
                        _t('EcommerceDBConfig.EMAILS', 'Emails'),
470
                        new TextField('ReceiptEmail', $fieldLabels['ReceiptEmail']),
471
                        new UploadField('EmailLogo', $fieldLabels['EmailLogo'], null, null, null, 'logos'),
0 ignored issues
show
The call to UploadField::__construct() has too many arguments starting with null.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
472
                        new TextField('InvoiceTitle', $fieldLabels['InvoiceTitle']),
473
                        $htmlEditorField5 = new HTMLEditorField('InvoiceMessage', $fieldLabels['InvoiceMessage'])
474
                    ),
475
                    Tab::create(
476
                        'Process',
477
                        _t('EcommerceDBConfig.PROCESS', 'Process'),
478
                        $self->getOrderStepsField()
479
                    ),
480
                    Tab::create(
481
                        'Advanced',
482
                        _t('EcommerceDBConfig.ADVANCED', 'Advanced'),
483
                        new LiteralField(
484
                            'ReviewHardcodedSettings',
485
                            '<p>
486
                                Your developer has pre-set some configurations for you.
487
                                You can
488
                                <a href="/dev/ecommerce/ecommercetaskcheckconfiguration" data-popup="true">review these settings</a>
489
                                but you will need to ask your developer to change them if they are not right.
490
                                The reason they can not be set is that changing them can break your application.
491
                            </p>'
492
                        )
493
                    )
494
                ));
495
                $mappingArray = Config::inst()->get('BillingAddress', 'fields_to_google_geocode_conversion');
496
                if (is_array($mappingArray) && count($mappingArray)) {
497
                    $mappingArray = Config::inst()->get('ShippingAddress', 'fields_to_google_geocode_conversion');
498
                    if (is_array($mappingArray) && count($mappingArray)) {
499
                        $fields->removeByName('PostalCodeURL');
500
                        $fields->removeByName('PostalCodeLabel');
501
                    }
502
                }
503
                $htmlEditorField1->setRows(3);
504
                $htmlEditorField2->setRows(3);
505
                $htmlEditorField3->setRows(3);
506
                $htmlEditorField4->setRows(3);
507
                $htmlEditorField5->setRows(3);
508
                $fields->addFieldsToTab(
509
                    'Root.Main',
510
                    array(
511
                        new CheckboxField('UseThisOne', $fieldLabels['UseThisOne']),
512
                        new CheckboxField('ShopClosed', $fieldLabels['ShopClosed']),
513
                        $clearField = ReadonlyField::create(
514
                            'RefreshWebsite',
515
                            'Update site',
516
                            '<h2><a href="/shoppingcart/clear/?flush=all" target="_blank">Refresh website / clear caches</a></h2>'
517
                        )
518
                    )
519
                );
520
                $clearField->dontEscape = true;
521
                //set cols
522
                if ($f = $fields->dataFieldByName('CurrenciesExplanation')) {
523
                    $f->setRows(2);
524
                }
525
                if ($f = $fields->dataFieldByName('NotForSaleMessage')) {
526
                    $f->setRows(2);
527
                }
528
                if ($f = $fields->dataFieldByName('ShopPhysicalAddress')) {
529
                    $f->setRows(2);
530
                }
531
                foreach ($fields->dataFields() as $field) {
532
                    if (isset($fieldDescriptions[$field->getName()])) {
533
                        if ($field instanceof CheckboxField) {
534
                            $field->setDescription($fieldDescriptions[$field->Name]);
535
                        } else {
536
                            $field->setRightTitle($fieldDescriptions[$field->Name]);
537
                        }
538
                    }
539
                }
540
                Requirements::block('ecommerce/javascript/EcomPrintAndMail.js');
541
                if (strnatcmp(phpversion(), '5.5.1') >= 0) {
542
                    $fields->addFieldToTab('Root.ProductImages', new Product_ProductImageUploadField('DefaultProductImage', $fieldLabels['DefaultProductImage'], null, null, null, 'default-product-image'));
0 ignored issues
show
The call to Product_ProductImageUploadField::__construct() has too many arguments starting with null.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
543
                }
544
                $fields->replaceField(
545
                    'UseThisOne',
546
                    HiddenField::create(
547
                        'UseThisOne',
548
                        'UseThisOne'
549
                    )
550
                );
551
            }
552
        );
553
        return parent::getCMSFields();
554
    }
555
556
    /**
557
     * link to edit the record.
558
     *
559
     * @param string | Null $action - e.g. edit
560
     *
561
     * @return string
562
     */
563
    public function CMSEditLink($action = null)
564
    {
565
        return '/admin/shop/EcommerceDBConfig/';
566
    }
567
568
    public function getOrderStepsField()
569
    {
570
        $gridFieldConfig = GridFieldConfig::create()->addComponents(
571
            new GridFieldToolbarHeader(),
572
            new GridFieldSortableHeader(),
573
            new GridFieldDataColumns(10),
0 ignored issues
show
The call to GridFieldDataColumns::__construct() has too many arguments starting with 10.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
574
            new GridFieldPaginator(10),
575
            new GridFieldEditButton(),
576
            new GridFieldDeleteAction(),
577
            new GridFieldDetailForm()
578
        );
579
580
        return new GridField('OrderSteps', _t('OrderStep.PLURALNAME', 'Order Steps'), OrderStep::get(), $gridFieldConfig);
581
    }
582
583
    /**
584
     * tells us if a Class Name is a buyable.
585
     *
586
     * @todo: consider using Ecomerce Configuration instead?
587
     * In EcomConfig we only list base classes.
588
     *
589
     * @param string $className - name of the class to be tested
590
     *
591
     * @return bool
592
     */
593
    public static function is_buyable($className)
594
    {
595
        $implementorsArray = class_implements($className);
596
        if (is_array($implementorsArray) && in_array('BuyableModel', $implementorsArray)) {
0 ignored issues
show
This if statement, and the following return statement can be replaced with return is_array($impleme...', $implementorsArray);.
Loading history...
597
            return true;
598
        }
599
600
        return false;
601
    }
602
603
    /**
604
     * Returns the Current Member.
605
     */
606
    public function Customer()
607
    {
608
        return Member::currentUser();
609
    }
610
611
    /**
612
     * Returns the Current Member.
613
     */
614
    public function CustomerForOrder()
0 ignored issues
show
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...
615
    {
616
        $order = ShoppingCart::current_order();
617
618
        return $order->Member();
0 ignored issues
show
The method Member() does not exist on Order. Did you maybe mean CreateOrReturnExistingMember()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
619
    }
620
621
    /**
622
     * Return the currency being used on the site e.g. "NZD" or "USD".
623
     *
624
     * @return string
0 ignored issues
show
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...
625
     */
626
    public function Currency()
627
    {
628
        return EcommerceConfig::get('EcommerceCurrency', 'default_currency');
629
    }
630
631
    /**
632
     * return null if there is less than two currencies in use
633
     * on the site.
634
     *
635
     * @return DataList | Null
0 ignored issues
show
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...
636
     */
637
    public function Currencies()
638
    {
639
        $list = EcommerceCurrency::get_list();
640
        if ($list && $list->count() > 1) {
641
            return $list;
642
        }
643
    }
644
645
    /**
646
     * @return string (URLSegment)
647
     **/
648
    public function AccountPageLink()
649
    {
650
        return AccountPage::find_link();
651
    }
652
653
    /**
654
     * @return string (URLSegment)
655
     **/
656
    public function CheckoutLink()
657
    {
658
        return CheckoutPage::find_link();
659
    }
660
661
    /**
662
     *@return string (URLSegment)
663
     **/
664
    public function CartPageLink()
665
    {
666
        return CartPage::find_link();
667
    }
668
669
    /**
670
     *@return string (URLSegment)
671
     **/
672
    public function OrderConfirmationPageLink()
673
    {
674
        return OrderConfirmationPage::find_link();
675
    }
676
677
    /**
678
     * Returns a link to a default image.
679
     * If a default image is set in the site config then this link is returned
680
     * Otherwise, a standard link is returned.
681
     *
682
     * @return string
683
     */
684
    public function DefaultImageLink()
685
    {
686
        if ($this->DefaultProductImageID) {
0 ignored issues
show
The property DefaultProductImageID does not exist on object<EcommerceDBConfig>. 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...
687
            $defaultImage = $this->DefaultProductImage();
0 ignored issues
show
Documentation Bug introduced by
The method DefaultProductImage does not exist on object<EcommerceDBConfig>? 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...
688
            if ($defaultImage && $defaultImage->exists()) {
689
                return $defaultImage->Link();
690
            }
691
        }
692
693
        return 'ecommerce/images/productPlaceHolderThumbnail.gif';
694
    }
695
696
    /**
697
     * Returns the default image or a dummy one if it does not exists.
698
     *
699
     * @return string
700
     */
701
    public function DefaultImage()
702
    {
703
        if ($this->DefaultProductImageID) {
0 ignored issues
show
The property DefaultProductImageID does not exist on object<EcommerceDBConfig>. 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...
704
            if ($defaultImage = $this->DefaultProductImage()) {
0 ignored issues
show
Documentation Bug introduced by
The method DefaultProductImage does not exist on object<EcommerceDBConfig>? 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...
705
                if ($defaultImage->exists()) {
706
                    return $defaultImage;
707
                }
708
            }
709
        }
710
        $obj = Product_Image::create();
711
        $obj->Link = $this->DefaultImageLink();
0 ignored issues
show
The property Link does not exist on object<Product_Image>. 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...
712
        $obj->URL = $this->DefaultImageLink();
0 ignored issues
show
The property URL does not exist on object<Product_Image>. 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...
713
714
        return $obj;
715
    }
716
717
    /**
718
     * standard SS method.
719
     */
720
    public function onAfterWrite()
721
    {
722
        if ($this->UseThisOne) {
0 ignored issues
show
The property UseThisOne does not exist on object<EcommerceDBConfig>. 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...
723
            $configs = EcommerceDBConfig::get()
724
                ->Filter(array('UseThisOne' => 1))
725
                ->Exclude(array('ID' => $this->ID));
726
            if ($configs->count()) {
727
                foreach ($configs as $config) {
728
                    $config->UseThisOne = 0;
729
                    $config->write();
730
                }
731
            }
732
        }
733
        $configs = EcommerceDBConfig::get()
734
            ->Filter(array('Title' => $this->Title))
0 ignored issues
show
The property Title does not exist on object<EcommerceDBConfig>. 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...
735
            ->Exclude(array('ID' => $this->ID));
736
        if ($configs->count()) {
737
            foreach ($configs as $key => $config) {
738
                $config->Title = $config->Title.'_'.$config->ID;
739
                $config->write();
740
            }
741
        }
742
    }
743
744
    /**
745
     * standard SS Method.
746
     */
747
    public function requireDefaultRecords()
748
    {
749
        parent::requireDefaultRecords();
750
        if (!self::current_ecommerce_db_config()) {
751
            $obj = self::create();
752
            $obj->write();
753
        }
754
        DB::alteration_message(
755
            '
756
            <hr /><hr /><hr /><hr /><hr />
757
            <h1 style="color: darkRed">Please make sure to review your <a href="/dev/ecommerce/">e-commerce settings</a>.</h1>
758
            <hr /><hr /><hr /><hr /><hr />',
759
            'edited'
760
        );
761
    }
762
763
    /**
764
     * returns site config.
765
     *
766
     * @return SiteConfig
767
     */
768
    public function SiteConfig()
769
    {
770
        return SiteConfig::current_site_config();
771
    }
772
773
    /**
774
     * Casted Variable.
775
     *
776
     * @return string
777
     */
778
    public function UseThisOneNice()
779
    {
780
        return $this->UseThisOne ? 'YES' : 'NO';
0 ignored issues
show
The property UseThisOne does not exist on object<EcommerceDBConfig>. 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...
781
    }
782
}
783