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/process/OrderStatusLog.php (42 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
 * @description: see OrderStep.md
4
 *
5
 *
6
 * @authors: Nicolaas [at] Sunny Side Up .co.nz
7
 * @package: ecommerce
8
 * @sub-package: model
9
 * @inspiration: Silverstripe Ltd, Jeremy
10
 **/
11
class OrderStatusLog 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
        'Title' => 'Varchar(100)',
20
        'Note' => 'HTMLText',
21
        'InternalUseOnly' => 'Boolean',
22
    );
23
24
    /**
25
     * standard SS variable.
26
     *
27
     * @var array
28
     */
29
    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...
30
        'Author' => 'Member',
31
        'Order' => 'Order',
32
    );
33
34
    /**
35
     * standard SS variable.
36
     *
37
     * @var array
38
     */
39
    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...
40
        'CustomerNote' => 'HTMLText',
41
        'Type' => 'Varchar',
42
        'InternalUseOnlyNice' => 'Varchar',
43
    );
44
45
    /**
46
     * standard SS variable.
47
     *
48
     * @var array
49
     */
50
    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...
51
        'Created' => 'Date',
52
        'Order.Title' => 'Order',
53
        'Type' => 'Type',
54
        'Title' => 'Title',
55
        'InternalUseOnlyNice' => 'Internal use only',
56
    );
57
58
    /**
59
     * standard SS variable.
60
     *
61
     * @var array
62
     */
63
    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...
64
        'InternalUseOnly' => true,
65
    );
66
67
    /**
68
     * casted method.
69
     *
70
     * @return string
71
     */
72
    public function InternalUseOnlyNice()
73
    {
74
        return $this->getInternalUseOnlyNice();
75
    }
76
    public function getInternalUseOnlyNice()
77
    {
78
        if ($this->InternalUseOnly) {
0 ignored issues
show
The property InternalUseOnly does not exist on object<OrderStatusLog>. 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...
79
            return _t('OrderStatusLog.YES', 'Yes');
80
        }
81
82
        return _t('OrderStatusLog.No', 'No');
83
    }
84
85
    /**
86
     * Standard SS method.
87
     *
88
     * @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...
89
     *
90
     * @return bool
0 ignored issues
show
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...
91
     */
92
    public function canCreate($member = null)
93
    {
94
        if (! $member) {
95
            $member = Member::currentUser();
96
        }
97
        $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...
98
        if ($extended !== null) {
99
            return $extended;
100
        }
101
        if (Permission::checkMember($member, Config::inst()->get('EcommerceRole', 'admin_permission_code'))) {
102
            return true;
103
        }
104
        //is the member is a shop assistant they can always view it
105
        if (EcommerceRole::current_member_is_shop_assistant($member)) {
106
            return true;
107
        }
108
109
        return parent::canEdit($member);
0 ignored issues
show
It seems like $member defined by \Member::currentUser() on line 95 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...
110
    }
111
112
    /**
113
     * Standard SS method.
114
     *
115
     * @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...
116
     *
117
     * @return bool
0 ignored issues
show
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...
118
     */
119
    public function canView($member = null)
120
    {
121
        if (! $member) {
122
            $member = Member::currentUser();
123
        }
124
        $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...
125
        if ($extended !== null) {
126
            return $extended;
127
        }
128
        if (Permission::checkMember($member, Config::inst()->get('EcommerceRole', 'admin_permission_code'))) {
129
            return true;
130
        }
131
        //is the member is a shop assistant they can always view it
132
        if (EcommerceRole::current_member_is_shop_assistant($member)) {
133
            return true;
134
        }
135
        if ($this->InternalUseOnly) {
0 ignored issues
show
The property InternalUseOnly does not exist on object<OrderStatusLog>. Since you implemented __get, maybe consider adding a @property annotation.

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

<?php

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

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

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

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

}

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

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

See also the PhpDoc documentation for @property.

Loading history...
136
            //only Shop Administrators can see it ...
137
            return false;
138
        } else {
139
            if ($this->Order()) {
0 ignored issues
show
Documentation Bug introduced by
The method Order does not exist on object<OrderStatusLog>? 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...
140
                if ($this->Order()->canView($member)) {
0 ignored issues
show
Documentation Bug introduced by
The method Order does not exist on object<OrderStatusLog>? 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...
141
                    return true;
142
                }
143
            }
144
        }
145
146
        return parent::canView($member);
0 ignored issues
show
It seems like $member defined by \Member::currentUser() on line 122 can also be of type object<DataObject>; however, DataObject::canView() 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...
147
    }
148
149
    /**
150
     * Standard SS method.
151
     *
152
     * @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...
153
     *
154
     * @return bool
155
     */
156
    public function canEdit($member = null)
157
    {
158
        if (! $member) {
159
            $member = Member::currentUser();
160
        }
161
        $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...
162
        if ($extended !== null) {
163
            return $extended;
164
        }
165
166
        if ($order = $this->Order()) {
0 ignored issues
show
Documentation Bug introduced by
The method Order does not exist on object<OrderStatusLog>? 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...
167
            //Order Status Logs are so basic, anyone can edit them
168
            if ($this->ClassName=='OrderStatusLog') {
169
                return $order->canView($member);
170
            }
171
172
            if (Permission::checkMember($member, Config::inst()->get('EcommerceRole', 'admin_permission_code'))) {
173
                return $order->canEdit($member);
174
            }
175
        }
176
177
178
179
        return false;
180
    }
181
182
    /**
183
     * Standard SS method
184
     * logs can never be deleted...
185
     *
186
     * @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...
187
     *
188
     * @return bool
189
     */
190
    public function canDelete($member = null)
191
    {
192
        if (! $member) {
193
            $member = Member::currentUser();
194
        }
195
        $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...
196
        if ($extended !== null) {
197
            return $extended;
198
        }
199
200
        return false;
201
    }
202
203
    /**
204
     * standard SS variable.
205
     *
206
     * @var array
207
     */
208
    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...
209
        'OrderID' => array(
210
            'field' => 'NumericField',
211
            'title' => 'Order Number',
212
        ),
213
        'ClassName' => array(
214
            'title' => 'Type',
215
            'filter' => 'ExactMatchFilter',
216
        ),
217
        'Title' => 'PartialMatchFilter',
218
        'Note' => 'PartialMatchFilter',
219
    );
220
221
    /**
222
     * standard SS variable.
223
     *
224
     * @var string
225
     */
226
    private static $singular_name = 'Order Log Entry';
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...
227
    public function i18n_singular_name()
228
    {
229
        return _t('OrderStatusLog.ORDERLOGENTRY', 'Order Log Entry');
230
    }
231
232
    /**
233
     * standard SS variable.
234
     *
235
     * @var string
236
     */
237
    private static $plural_name = 'Order Log Entries';
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...
238
    public function i18n_plural_name()
239
    {
240
        return _t('OrderStatusLog.ORDERLOGENTRIES', 'Order Log Entries');
241
    }
242
243
    /**
244
     * Standard SS variable.
245
     *
246
     * @var string
247
     */
248
    private static $description = 'A record of anything that happened with an order.';
249
250
    /**
251
     * standard SS variable.
252
     *
253
     * @var string
254
     */
255
    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...
256
        'ID' => 'DESC'
257
    ];
258
259
    private static $indexes = [
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...
260
        'Title' => true,
261
        'InternalUseOnly' => true
262
    ];
263
264
    /**
265
     * standard SS method.
266
     */
267
    public function populateDefaults()
268
    {
269
        parent::populateDefaults();
270
        if (Security::database_is_ready()) {
271
            $this->AuthorID = Member::currentUserID();
0 ignored issues
show
The property AuthorID does not exist on object<OrderStatusLog>. 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...
272
        }
273
    }
274
275
    /**
276
     *@return FieldList
277
     **/
278
    public function getCMSFields()
279
    {
280
        $fields = parent::getCMSFields();
281
        $fields->dataFieldByName('Note')->setRows(3);
282
        $fields->dataFieldByName('Title')->setTitle('Subject');
283
        $fields->addFieldToTab(
284
            'Root.Main',
285
            DropdownField::create(
286
                'AuthorID',
287
                _t('OrderStatusLog.AUTHOR', 'Author'),
288
                EcommerceRole::list_of_admins(true)
289
            )
290
        );
291
        if ($this->AuthorID) {
0 ignored issues
show
The property AuthorID does not exist on object<OrderStatusLog>. 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...
292
            if ($this->Author() && $this->Author()->exists()) {
0 ignored issues
show
Documentation Bug introduced by
The method Author does not exist on object<OrderStatusLog>? 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...
293
                $fields->addFieldToTab(
294
                    'Root.Main',
295
                    $fields->dataFieldByName('AuthorID')->performReadonlyTransformation()
296
                );
297
            }
298
        }
299
300
        //OrderID Field
301
        if ($this->exists() && $this->OrderID) {
0 ignored issues
show
The property OrderID does not exist on object<OrderStatusLog>. 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...
302
            $order = $this->Order();
0 ignored issues
show
Documentation Bug introduced by
The method Order does not exist on object<OrderStatusLog>? 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...
303
            if ($order && $order->exists()) {
304
                $fields->removeByName('OrderID');
305
                $fields->addFieldToTab(
306
                    'Root.Main',
307
                    CMSEditLinkField::create('OrderID', $order->singular_name(), $order)
308
                );
309
            }
310
        }
311
312
        //ClassName Field
313
        $availableLogs = EcommerceConfig::get('OrderStatusLog', 'available_log_classes_array');
314
        $availableLogs = array_merge($availableLogs, array(EcommerceConfig::get('OrderStatusLog', 'order_status_log_class_used_for_submitting_order')));
315
        $availableLogsAssociative = array();
316
        foreach ($availableLogs as $className) {
317
            $availableLogsAssociative[$className] = Injector::inst()->get($className)->singular_name();
318
        }
319
        $title = _t('OrderStatusLog.TYPE', 'Type');
320
        if (
321
                ($this->exists() || $this->limitedToOneClassName())
322
                && $this->ClassName &&
323
                isset($availableLogsAssociative[$this->ClassName])
324
        ) {
325
            $fields->removeByName('ClassName');
326
            $fields->addFieldsToTab(
327
                'Root.Main',
328
                array(
329
                    HiddenField::create('ClassName'),
330
                    ReadonlyField::create(
331
                        'ClassNameTitle',
332
                        $title,
333
                        $availableLogsAssociative[$this->ClassName]
334
                    )
335
                ),
336
                'Title'
337
            );
338
        } else {
339
            $ecommerceClassNameOrTypeDropdownField = EcommerceClassNameOrTypeDropdownField::create(
340
                'ClassName',
341
                _t('OrderStatusLog.TYPE', 'Type'),
342
                'OrderStatusLog',
343
                $availableLogsAssociative
344
            );
345
            $ecommerceClassNameOrTypeDropdownField->setIncludeBaseClass(true);
346
            $fields->addFieldToTab('Root.Main', $ecommerceClassNameOrTypeDropdownField, 'Title');
347
        }
348
        return $fields;
349
    }
350
351
    /**
352
     * when being created, can the user choose the type of log?
353
     *
354
     *
355
     * @return bool
356
     */
357
    protected function limitedToOneClassName()
358
    {
359
        if ($this->ClassName == 'OrderStatusLog') {
0 ignored issues
show
This if statement, and the following return statement can be replaced with return !($this->ClassName == 'OrderStatusLog');.
Loading history...
360
            return false;
361
        }
362
        return true;
363
    }
364
365
    /**
366
     * link to edit the record.
367
     *
368
     * @param string | Null $action - e.g. edit
369
     *
370
     * @return string
0 ignored issues
show
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...
371
     */
372
    public function CMSEditLink($action = null)
373
    {
374
        return CMSEditLinkAPI::find_edit_link_for_object($this, $action);
375
    }
376
377
    /**
378
     * @return string
379
     **/
380
    public function Type()
381
    {
382
        return $this->getType();
383
    }
384
    public function getType()
385
    {
386
        return $this->i18n_singular_name();
387
    }
388
389
    /**
390
     * Determine which properties on the DataObject are
391
     * searchable, and map them to their default {@link FormField}
392
     * representations. Used for scaffolding a searchform for {@link ModelAdmin}.
393
     *
394
     * Some additional logic is included for switching field labels, based on
395
     * how generic or specific the field type is.
396
     *
397
     * Used by {@link SearchContext}.
398
     *
399
     * @param array $_params
0 ignored issues
show
Should the type for parameter $_params not be array|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...
400
     *                       'fieldClasses': Associative array of field names as keys and FormField classes as values
401
     *                       'restrictFields': Numeric array of a field name whitelist
402
     *
403
     * @return FieldList
404
     */
405
    public function scaffoldSearchFields($_params = null)
406
    {
407
        $fields = parent::scaffoldSearchFields($_params);
408
        $fields->replaceField('OrderID', NumericField::create('OrderID', 'Order Number'));
409
        $availableLogs = EcommerceConfig::get('OrderStatusLog', 'available_log_classes_array');
410
        $availableLogs = array_merge($availableLogs, array(EcommerceConfig::get('OrderStatusLog', 'order_status_log_class_used_for_submitting_order')));
411
        $ecommerceClassNameOrTypeDropdownField = EcommerceClassNameOrTypeDropdownField::create('ClassName', 'Type', 'OrderStatusLog', $availableLogs);
412
        $ecommerceClassNameOrTypeDropdownField->setIncludeBaseClass(true);
413
        $fields->replaceField('ClassName', $ecommerceClassNameOrTypeDropdownField);
414
415
        return $fields;
416
    }
417
418
    /**
419
     * standard SS method.
420
     */
421
    public function onBeforeWrite()
422
    {
423
        parent::onBeforeWrite();
424
//        //START HACK TO PREVENT LOSS OF ORDERID CAUSED BY COMPLEX TABLE FIELDS....
425
//        // THIS MEANS THAT A LOG CAN NEVER SWITCH FROM ONE ORDER TO ANOTHER...
426
//        if ($this->exists()) {
427
//            $orderID = $this->getField('OrderID');
428
//            if ($orderID) {
429
//                $this->OrderID = $orderID;
430
//            }
431
//        }
432
//        //END HACK TO PREVENT LOSS
433
        if (!$this->AuthorID) {
0 ignored issues
show
The property AuthorID does not exist on object<OrderStatusLog>. 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...
434
            if ($member = Member::currentUser()) {
435
                $this->AuthorID = $member->ID;
0 ignored issues
show
The property AuthorID does not exist on object<OrderStatusLog>. 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...
436
            }
437
        }
438
        if (!$this->Title) {
0 ignored issues
show
The property Title does not exist on object<OrderStatusLog>. 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...
439
            $this->Title = _t('OrderStatusLog.ORDERUPDATE', 'Order Update');
0 ignored issues
show
The property Title does not exist on object<OrderStatusLog>. 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...
440
        }
441
    }
442
443
    /**
444
     *@return string
445
     **/
446
    public function CustomerNote()
447
    {
448
        return $this->getCustomerNote();
449
    }
450
    public function getCustomerNote()
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...
451
    {
452
        return $this->Note;
0 ignored issues
show
The property Note does not exist on object<OrderStatusLog>. 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...
453
    }
454
455
    /**
456
     * returns the standard EcommerceDBConfig for use within OrderSteps.
457
     *
458
     * @return EcommerceDBConfig
459
     */
460
    protected function EcomConfig()
461
    {
462
        return EcommerceDBConfig::current_ecommerce_db_config();
463
    }
464
465
    /**
466
     * Debug helper method.
467
     * Can be called from /shoppingcart/debug/.
468
     *
469
     * @return string
470
     */
471
    public function debug()
472
    {
473
        return EcommerceTaskDebugCart::debug_object($this);
474
    }
475
}
476