Distributor   B
last analyzed

Complexity

Total Complexity 52

Size/Duplication

Total Lines 402
Duplicated Lines 2.49 %

Coupling/Cohesion

Components 1
Dependencies 25

Importance

Changes 0
Metric Value
wmc 52
lcom 1
cbo 25
dl 10
loc 402
rs 7.44
c 0
b 0
f 0

14 Methods

Rating   Name   Duplication   Size   Complexity  
A i18n_singular_name() 0 4 1
A i18n_plural_name() 0 4 1
A get_one_for_country() 0 11 4
A get_default_distributor() 0 4 1
C getCMSFields() 0 104 11
A getCountryList() 0 6 2
A CMSEditLink() 0 8 1
A onBeforeWrite() 0 18 6
A onAfterWrite() 0 8 2
A canDelete() 0 4 2
B requireDefaultRecords() 10 57 10
A get_distributor_group() 0 7 1
A providePermissions() 0 11 1
B setupUser() 0 34 9

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

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

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

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

1
<?php
2
3
/**
4
 * A country can only be sent goods to from 1 distributor + the default distributor which can send anywhere in the world.
5
 * The default distributor shows prices of the default currency.
6
 * Precondition : There is always a default distributor.
7
 */
8
class Distributor extends DataObject implements PermissionProvider
9
{
10
    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...
11
        'Name' => 'Varchar(255)',
12
        'IsDefault' => 'Boolean',
13
        'Email' => 'Varchar(200)',
14
        'Address1' => "Varchar((255)",
15
        'Address2' => "Varchar(255)",
16
        'Address3' => "Varchar(255)",
17
        'Address4' => "Varchar(255)",
18
        'Address5' => "Varchar(255)",
19
        'Phone' => "Varchar(50)",
20
        'DisplayEmail' => "Varchar(50)",
21
        'WebAddress' => "Varchar(255)",
22
        'DeliveryCostNote' => 'Varchar(255)',
23
        'ShippingEstimation' => 'Varchar(255)',
24
        'ReturnInformation' => 'Varchar(255)'
25
    );
26
27
    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...
28
        'PrimaryCountry' => 'EcommerceCountry'
29
    );
30
31
    private static $has_many = 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...
32
        'Countries' => 'EcommerceCountry',
33
        'Members' => 'Member',
34
        'Updates' => 'CountryPrice_DistributorManagementTool_Log'
35
    );
36
37
    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...
38
        'IsDefault' => 'Is Default Distributor?'
39
    );
40
41
    private static $field_labels_right = array(
42
        'IsDefault' => 'Use this only for the  distributor that is applicable when no other distributor applies (e.g. a country that does not have a distributor).',
43
        'Phone' => 'Please format as +64 8 555 5555'
44
    );
45
46
    private static $extensions = array("Versioned('Stage')");
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...
47
48
    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...
49
        "Name" => "Name",
50
        "IsDefault.Nice" => "Default"
51
    );
52
53
    private static $default_sort = 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...
54
        "IsDefault" => "DESC",
55
        "Name" => "Asc"
56
    );
57
58
59
    private static $singular_name = "Distributor";
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...
60
61
    /**
62
     * Return the translated Singular name.
63
     *
64
     * @return string
65
     */
66
    public function i18n_singular_name()
67
    {
68
        return _t('Distributor.SINGULAR_NAME', 'Distributor');
69
    }
70
71
72
    private static $plural_name = "Distributors";
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...
73
74
    /**
75
     * Return the translated Singular name.
76
     *
77
     * @return string
78
     */
79
    public function i18n_plural_name()
80
    {
81
        return _t('Distributor.PLURAL_NAME', 'Distributors');
82
    }
83
84
85
    /**
86
     * returns the Distributor for the country OR the default Distributor.
87
     * @param String $countryCode = the country code.
88
     *
89
     * @return Distributor
90
     */
91
    public static function get_one_for_country($countryCode = '')
92
    {
93
        $countryObject = CountryPrice_EcommerceCountry::get_real_country($countryCode);
94
        if ($countryObject) {
95
            $distributor = $countryObject->Distributor();
96
            if ($distributor && $distributor->exists()) {
97
                return $distributor;
98
            }
99
        }
100
        return self::get_default_distributor();
101
    }
102
103
    public static function get_default_distributor()
104
    {
105
        return  DataObject::get_one('Distributor', array("IsDefault" => 1));
106
    }
107
108
    public function getCMSFields()
109
    {
110
        $fields = parent::getCMSFields();
111
        $fieldLabels = $this->FieldLabels();
0 ignored issues
show
Unused Code introduced by
$fieldLabels 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...
112
        $fieldLabelsRight = $this->Config()->get("field_labels_right");
113
        $listOfCountriesCovered = EcommerceCountry::get()->exclude(array("DistributorID" => 0))->map("ID", "Title");
114
        //secondary for another country
115
        $fields->removeByName('Versions');
116
        if ($listOfCountriesCovered && $listOfCountriesCovered->count()) {
117
            $countryArray =  array(" -- please select --") + $listOfCountriesCovered->toArray();
118
            $fields->addFieldToTab("Root.CountryDetails", DropdownField::create("PrimaryCountryID", "Primary Country", $countryArray));
119
        } else {
120
            $fields->removeByName('PrimaryCountryID');
121
        }
122
        if ($this->IsDefault) {
0 ignored issues
show
Documentation introduced by
The property IsDefault does not exist on object<Distributor>. 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...
123
            $fields->removeByName('Countries');
124
        } else {
125
            if (empty($this->ID)) {
126
                $id = 0;
0 ignored issues
show
Unused Code introduced by
$id 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...
127
            } else {
128
                $id = $this->ID;
0 ignored issues
show
Unused Code introduced by
$id 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...
129
            }
130
            if ($this->ID) {
131
                $config = GridFieldConfig_RelationEditor::create();
132
                $config->removeComponentsByType("GridFieldAddNewButton");
133
                $gridField = new GridField('pages', 'All pages', SiteTree::get(), $config);
0 ignored issues
show
Unused Code introduced by
$gridField 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...
134
                $countryField = new GridField(
135
                    'Countries',
136
                    'Countries',
137
                    $this->Countries(),
0 ignored issues
show
Documentation Bug introduced by
The method Countries does not exist on object<Distributor>? 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...
138
                    $config
139
                );
140
                $fields->addFieldToTab("Root.CountryDetails", $countryField);
141
                if ($this->Version > 1) {
0 ignored issues
show
Documentation introduced by
The property Version does not exist on object<Distributor>. Since you implemented __get, maybe consider adding a @property annotation.

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

<?php

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

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

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

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

}

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

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

See also the PhpDoc documentation for @property.

Loading history...
142
                    $columns = array(
143
                        'Version' => 'Version',
144
                        'LastEdited' => 'Date',
145
                        'Name' => 'Name',
146
                        'IsDefault' => 'Default',
147
                        'Email' => 'Email'
148
                    );
149
                    $table = '<table class="versions"><thead><tr><th>' . implode('</th><th>', $columns) . '</th></tr></thead><tbody>';
150
                    $version = $this->Version - 1;
0 ignored issues
show
Documentation introduced by
The property Version does not exist on object<Distributor>. 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...
151
                    while ($version > 0) {
152
                        $versionDO = Versioned::get_version('Distributor', $this->ID, $version--);
153
                        $values = array();
154
                        foreach ($columns as $column => $title) {
155
                            $values[] = $versionDO->$column;
156
                        }
157
                        $table .= '<tr><td>' . implode('</td><td>', $values) . '</td></tr>';
158
                    }
159
                    $table .= '</tbody></table>';
160
                    $table .= "<style type=\"text/css\">
161
                                table.versions {border: 1px solid black; width:100%; border-collapse: collapse;}
162
                                table.versions tr {border: 1px solid black;}
163
                                table.versions tr th, table.versions tr td {border: 1px solid black; width: auto; text-align: center;}
164
                               </style>";
165
                    $fields->addFieldToTab('Root.Versions', new LiteralField('VersionsTable', $table));
166
                }
167
            }
168
        }
169
        $fields->addFieldsToTab(
170
            "Root.ContactDetails",
171
            array(
172
                new TextField("DisplayEmail"),
173
                new TextField("Phone"),
174
                new TextField("Address1"),
175
                new TextField("Address2"),
176
                new TextField("Address3"),
177
                new TextField("Address4"),
178
                new TextField("Address5")
179
            )
180
        );
181
        $fields->addFieldsToTab(
182
            "Root.EcomInfo",
183
            array(
184
                new TextField("DeliveryCostNote"),
185
                new TextField("ShippingEstimation"),
186
                new TextField("ReturnInformation"),
187
                new HTMLEditorField("ProductNotAvailableNote")
188
            )
189
        );
190
        foreach ($fieldLabelsRight as $key => $value) {
191
            $field = $fields->dataFieldByName($key);
192
            if ($field) {
193
                $field->setRightTitle($value);
194
            }
195
        }
196
        $fields->removeFieldFromTab(
197
            'Root',
198
            'Countries'
199
        );
200
        $fields->addFieldToTab(
201
            'Root.Main',
202
            $distributorsAdminLink = ReadonlyField::create(
203
                'distributors-admin-link',
204
                'Manage Prices',
205
                '<h2><a href="/distributors-admin/" target="_blank">Distributor Price Admin</a></h2>'
206
            )
207
        );
208
        $distributorsAdminLink->dontEscape = true;
209
210
        return $fields;
211
    }
212
213
    /**
214
     * returns EcommerceCountries that this Distributor is responsible for.
215
     * return ArrayList
216
     */
217
    public function getCountryList()
218
    {
219
        $filter = $this->IsDefault ? array("ID" => 0) : array("DistributorID" => $this->ID);
0 ignored issues
show
Documentation introduced by
The property IsDefault does not exist on object<Distributor>. 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...
Unused Code introduced by
$filter 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...
220
        return EcommerceCountry::get()
221
            ->filter($array);
0 ignored issues
show
Bug introduced by
The variable $array does not exist. Did you forget to declare it?

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

Loading history...
222
    }
223
224
    /**
225
     * link to edit the record
226
     * @param String | Null $action - e.g. edit
227
     * @return String
228
     */
229
    public function CMSEditLink($action = null)
230
    {
231
        return Controller::join_links(
232
            Director::baseURL(),
233
            "/admin/shop/".$this->ClassName."/EditForm/field/".$this->ClassName."/item/".$this->ID."/",
234
            $action
235
        );
236
    }
237
238
    /**
239
     * ensure there is one default Distributor.
240
     *
241
     */
242
    public function onBeforeWrite()
243
    {
244
        parent::onBeforeWrite();
245
        if (Distributor::get()->filter(array("IsDefault" => 1))->count() == 0) {
246
            $this->IsDefault = 1;
0 ignored issues
show
Documentation introduced by
The property IsDefault does not exist on object<Distributor>. 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...
247
        }
248
        if ($this->PrimaryCountryID > 0 && EcommerceCountry::get()->byID(intval($this->PrimaryCountryID))) {
0 ignored issues
show
Documentation introduced by
The property PrimaryCountryID does not exist on object<Distributor>. 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...
249
            $primaryCountry = $this->PrimaryCountry();
0 ignored issues
show
Documentation Bug introduced by
The method PrimaryCountry does not exist on object<Distributor>? 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...
250
            if (! $this->Countries()->byID($this->PrimaryCountryID)) {
0 ignored issues
show
Documentation introduced by
The property PrimaryCountryID does not exist on object<Distributor>. 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...
Documentation Bug introduced by
The method Countries does not exist on object<Distributor>? 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...
251
                $this->Countries()->add($primaryCountry);
0 ignored issues
show
Documentation Bug introduced by
The method Countries does not exist on object<Distributor>? 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...
252
            }
253
        } else {
254
            if ($firstCountry = $this->Countries()->First()) {
0 ignored issues
show
Documentation Bug introduced by
The method Countries does not exist on object<Distributor>? 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...
255
                self::$_ran_after_write = true;
256
                $this->PrimaryCountryID = $firstCountry->ID;
0 ignored issues
show
Documentation introduced by
The property PrimaryCountryID does not exist on object<Distributor>. 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...
257
            }
258
        }
259
    }
260
261
    private static $_ran_after_write = false;
262
    /**
263
     * ensure there is one default Distributor.
264
     *
265
     */
266
    public function onAfterWrite()
267
    {
268
        parent::onAfterWrite();
269
        if (! self::$_ran_after_write) {
270
            self::$_ran_after_write = true;
271
            $this->setupUser();
272
        }
273
    }
274
275
    /**
276
     * @param Member $member
0 ignored issues
show
Documentation introduced by
Should the type for parameter $member not be Member|null?

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

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

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

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

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

Loading history...
278
     */
279
    public function canDelete($member = null)
280
    {
281
        return $this->IsDefault ? false : parent::canEdit($member);
0 ignored issues
show
Documentation introduced by
The property IsDefault does not exist on object<Distributor>. 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...
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...
282
    }
283
284
    public function requireDefaultRecords()
285
    {
286
        parent::RequireDefaultRecords();
287
        $distributorTitleSingular = _t('Distributor.SINGULAR_NAME', 'Distributor');
288
        $distributorTitlePlural = _t('Distributor.PLURAL_NAME', 'Distributors');
289
        $filter = array("Title" => $distributorTitleSingular);
290
        $role = PermissionRole::get()->filter($filter)->first();
291 View Code Duplication
        if (!$role) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
292
            $role = PermissionRole::create($filter);
293
            $role->write();
294
            DB::alteration_message("Creating ".$distributorTitleSingular." role", 'created');
295
        }
296
        $codes = array(
297
            'CMS_ACCESS_SalesAdmin',
298
            'CMS_ACCESS_SalesAdminExtras',
299
            'CMS_ACCESS_SalesAdmin_PROCESS'
300
        );
301
        foreach ($codes as $code) {
302
            $filter = array(
303
                "RoleID" => $role->ID,
304
                "Code" => $code
305
            );
306
            $code = PermissionRoleCode::get()->filter($filter)->first();
307 View Code Duplication
            if (!$code) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
308
                DB::alteration_message("Adding code to ".$distributorTitleSingular." role", 'created');
309
                $code = PermissionRoleCode::create($filter);
310
                $code->write();
311
            }
312
        }
313
314
        $distributorGroup = self::get_distributor_group();
315
        $distributorPermissionCode = Config::inst()->get('Distributor', 'distributor_permission_code');
316
        if (!$distributorGroup) {
317
            $distributorGroup = new Group();
318
            $distributorGroup->Code = $distributorPermissionCode;
319
            $distributorGroup->Title = $distributorTitlePlural;
320
            $distributorGroup->write();
321
            DB::alteration_message($distributorTitlePlural.' Group created', "created");
322
            Permission::grant($distributorGroup->ID, $distributorPermissionCode);
323
        } elseif (DB::query("SELECT * FROM \"Permission\" WHERE \"GroupID\" = '".$distributorGroup->ID."' AND \"Code\" LIKE '".$distributorPermissionCode."'")->numRecords() == 0) {
324
            Permission::grant($distributorGroup->ID, $distributorPermissionCode);
325
            DB::alteration_message($distributorTitlePlural.' group permissions granted', "created");
326
        }
327
        $distributorGroup->Roles()->add($role);
328
        $distributorGroup = self::get_distributor_group();
329
        if (!$distributorGroup) {
330
            user_error("could not create user group");
331
        } else {
332
            DB::alteration_message('distributor group is ready for use');
333
        }
334
        $distributors = Distributor::get();
335
        if ($distributors && $distributors->count()) {
336
            foreach ($distributors as $distributor) {
337
                $distributor->setupUser();
338
            }
339
        }
340
    }
341
342
343
    /**
344
     * @return DataObject (Group)
0 ignored issues
show
Documentation introduced by
Should the return type not be DataObject|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...
345
     **/
346
    public static function get_distributor_group()
347
    {
348
        $distributorPermissionCode = Config::inst()->get('Distributor', 'distributor_permission_code');
349
        return Group::get()
350
            ->where("\"Code\" = '".$distributorPermissionCode."'")
351
            ->First();
352
    }
353
354
355
    /**
356
     * @var string
357
     */
358
    private static $distributor_permission_code = "distributors";
359
360
    /**
361
     * {@inheritdoc}
362
     */
363
    public function providePermissions()
364
    {
365
        return array(
366
            $perms[Config::inst()->get('Distributor', 'distributor_permission_code')] = array(
0 ignored issues
show
Coding Style Comprehensibility introduced by
$perms was never initialized. Although not strictly required by PHP, it is generally a good practice to add $perms = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
367
                'name' => _t('Distributor.PLURAL_NAME', 'Distributors'),
368
                'category' => 'E-commerce',
369
                'help' => _t('Distributor.SINGULAR_NAME', 'Distributor').' access to relevant products and sales data.',
370
                'sort' => 98,
371
            )
372
        );
373
    }
374
375
    public function setupUser()
376
    {
377
        $group = Group::get()->filter(array("Code" => $this->Config()->get('distributor_permission_code')))->first();
378
        if ($this->Email) {
0 ignored issues
show
Documentation introduced by
The property Email does not exist on object<Distributor>. 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...
379
            $filter = array("Email" => $this->Email);
0 ignored issues
show
Documentation introduced by
The property Email does not exist on object<Distributor>. 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...
380
            $member = Member::get()
381
                ->filter($filter)
382
                ->First();
383
            if (!$member) {
384
                $member = Member::create($filter);
385
                //$thisMember->SetPassword = substr(session_id, 0, 8);
386
            }
387
            $member->FirstName = trim(_t('Distributor.SINGULAR_NAME', 'Distributor') . _t('Distributor.FOR', ' for '));
388
            $member->Surname = $this->Name;
0 ignored issues
show
Documentation introduced by
The property Name does not exist on object<Distributor>. 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...
389
            $member->DistributorID = $this->ID;
390
            $member->write();
391
            if ($group) {
392
                $member->addToGroupByCode($group->Code);
393
            }
394
            $member->write();
395
        }
396
        if ($group) {
397
            foreach ($group->Members() as $oldGroupMember) {
398
                $distributor = $oldGroupMember->Distributor();
399
                if ($distributor && $distributor->exists()) {
400
                } else {
401
                    $group->Members()->remove($oldGroupMember);
402
                }
403
            }
404
            foreach ($this->Members() as $member) {
0 ignored issues
show
Documentation Bug introduced by
The method Members does not exist on object<Distributor>? 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...
405
                $member->addToGroupByCode($group->Code);
406
            }
407
        }
408
    }
409
}
410