CampaignMonitorSyncAllMembers   C
last analyzed

Complexity

Total Complexity 60

Size/Duplication

Total Lines 323
Duplicated Lines 18.58 %

Coupling/Cohesion

Components 1
Dependencies 7

Importance

Changes 0
Metric Value
wmc 60
lcom 1
cbo 7
dl 60
loc 323
rs 6.0975
c 0
b 0
f 0

6 Methods

Rating   Name   Duplication   Size   Complexity  
C run() 0 71 15
A getAPI() 0 8 2
C getExistingFolkListed() 0 31 8
C getBouncedSubscribers() 27 27 7
C getUnsubscribedSubscribers() 27 27 7
D exportNow() 6 83 21

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 CampaignMonitorSyncAllMembers 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 CampaignMonitorSyncAllMembers, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/**
4
 * Moves all Members to a Campaign Monitor List
5
 *
6
 * Requires the Member Object
7
 * to have a method `IsBlackListed`
8
 * to unsubscribe anyone you do not want to add
9
 * to newsletter.
10
 *
11
 * You can extend this basic task to
12
 * add more functionality
13
 *
14
 */
15
16
class CampaignMonitorSyncAllMembers extends BuildTask
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

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

namespace YourVendor;

class YourClass { }

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

Loading history...
17
{
18
19
20
    /**
21
     * The default page of where the members are added.
22
     * @var Int
23
     */
24
    private static $mailing_list_id = "";
0 ignored issues
show
Unused Code introduced by
The property $mailing_list_id is not used and could be removed.

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

Loading history...
25
26
    protected $title = "Export Newsletter to Campaign Monitor";
27
28
    protected $description = "Moves all the Members to campaign monitor";
29
30
    /**
31
     * @var Boolean
32
     */
33
    protected $debug = true;
34
35
    /**
36
     * @var Boolean
37
     */
38
    protected $enabled = false;
39
40
    /**
41
     * @var array
42
     */
43
    protected $previouslyExported = array();
44
45
    /**
46
     * @var array
47
     */
48
    protected $previouslyUnsubscribedSubscribers = array();
49
50
    /**
51
     * @var array
52
     */
53
    protected $previouslyBouncedSubscribers = array();
54
55
    /**
56
     *
57
     */
58
    public function run($request)
59
    {
60
        increase_time_limit_to(3600);
61
        increase_memory_limit_to('5120M');
62
        $this->getUnsubscribedSubscribers();
63
        $this->getExistingFolkListed();
64
        $this->getBouncedSubscribers();
65
        DB::alteration_message("Number of active recipients already exported: ".count($this->previouslyExported), "created");
66
        DB::alteration_message("Number of recipients already unsubscribed: ".count($this->previouslyUnsubscribedSubscribers), "created");
67
        DB::alteration_message("Number of recipients already bounced: ".count($this->previouslyBouncedSubscribers), "created");
68
69
        if (Director::isLive()) {
70
            $this->debug = false;
71
        }
72
        if ($this->debug) {
73
            $limit = 20;
74
            $maxIterations = 20;
75
            DB::alteration_message("Running in debug mode going to check $maxIterations loops of $limit records.");
76
        } else {
77
            $limit = 400;
78
            $maxIterations = 1000000;
79
            DB::alteration_message("Running in live mode going to check $maxIterations loops of $limit records.");
80
        }
81
        $customFields = array();
82
        $memberArray = array();
83
        $unsubscribeArray = array();
84
        $alreadyCompleted = array();
85
        for ($i = 0; $i < $maxIterations; $i++) {
86
            $members = Member::get()
87
                ->limit($limit, $i * $limit);
88
            if ($this->debug) {
89
                $members = $members->sort("RAND()");
90
            }
91
            if ($members->count()) {
92
                foreach ($members as $member) {
93
                    if (isset($this->previouslyUnsubscribedSubscribers[$member->Email])) {
94
                        DB::alteration_message("already blacklisted: ".$member->Email, "deleted");
95
                    } elseif (isset($this->previouslyBouncedSubscribers[$member->Email])) {
96
                        DB::alteration_message("deleting bounced member: ".$member->Email, "deleted");
97
                        if (!$this->debug) {
98
                            $api->deleteSubscriber(Config::inst()->get("CampaignMonitorSyncAllMembers", "mailing_list_id"), $member->Email);
0 ignored issues
show
Bug introduced by
The variable $api 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...
99
                        }
100
                    } else {
101
                        if (!isset($alreadyCompleted[$member->Email])) {
102
                            $alreadyCompleted[$member->Email] = true;
103
                            $customFields[$member->Email] = array(
104
                                "Email" => $member->Email,
105
                                "FirstName" =>  $member->FirstName,
106
                                "Surname" =>  $member->Surname
107
                            );
108
                            if (!$member instanceof Member) {
109
                                user_error("Member not instance of Member");
110
                            }
111
                            $memberArray[$member->Email] = $member;
112
                        }
113
                        if ($member->Email && $member->hasMethod("IsBlackListed") && $member->IsBlackListed()) {
114
                            $unsubscribeArray[$member->Email] = $member;
115
                            DB::alteration_message("Blacklisting: ".$member->Email, "deleted");
116
                        }
117
                    }
118
                }
119
                $this->exportNow($memberArray, $customFields, $unsubscribeArray);
120
                $customFields = array();
121
                $memberArray = array();
122
                $unsubscribeArray = array();
123
            } else {
124
                $i = $maxIterations + 1;
125
            }
126
        }
127
        DB::alteration_message("<h1>== THE END ==</h1>");
128
    }
129
130
    private static $_api = null;
131
132
    /**
133
     *
134
     * @return CampaignMonitorAPIConnector
135
     */
136
    public function getAPI()
137
    {
138
        if (!self::$_api) {
139
            self::$_api = CampaignMonitorAPIConnector::create();
140
            self::$_api->init();
141
        }
142
        return self::$_api;
143
    }
144
145
    /**
146
     * updates the previouslyExported variable
147
     * @return null
148
     */
149
    private function getExistingFolkListed()
150
    {
151
        $array = array();
0 ignored issues
show
Unused Code introduced by
$array 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...
152
        $api = $this->getAPI();
153
        for ($i = 1; $i < 100; $i++) {
154
            $list = $api->getActiveSubscribers(
155
                $listID = Config::inst()->get("CampaignMonitorSyncAllMembers", "mailing_list_id"),
156
                $daysAgo = 3650,
157
                $page = $i,
158
                $pageSize = 999,
159
                $sortByField = "Email",
160
                $sortDirection = "ASC"
161
            );
162
            if (isset($list->NumberOfPages) && $list->NumberOfPages) {
163
                if ($i > $list->NumberOfPages) {
0 ignored issues
show
Bug introduced by
The property NumberOfPages does not seem to exist in CS_REST_Wrapper_Result.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
164
                    $i = 999999;
165
                }
166
            }
167
            if (isset($list->Results)) {
168
                foreach ($list->Results as $obj) {
0 ignored issues
show
Bug introduced by
The property Results does not seem to exist in CS_REST_Wrapper_Result.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
169
                    $finalCustomFields = array();
170
                    foreach ($obj->CustomFields as $customFieldObject) {
171
                        $finalCustomFields[str_replace(array("[", "]"), "", $customFieldObject->Key)] = $customFieldObject->Value;
172
                    }
173
                    $this->previouslyExported[$obj->EmailAddress] = $finalCustomFields;
174
                }
175
            } else {
176
                return;
177
            }
178
        }
179
    }
180
181
182
    /**
183
     * updates previouslyBouncedSubscribers variable
184
     *
185
     * @return null
186
     */
187 View Code Duplication
    private function getBouncedSubscribers()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
188
    {
189
        $array = array();
0 ignored issues
show
Unused Code introduced by
$array 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...
190
        $api = $this->getAPI();
191
        for ($i = 1; $i < 100; $i++) {
192
            $list = $api->getBouncedSubscribers(
193
                $listID = Config::inst()->get("CampaignMonitorSyncAllMembers", "mailing_list_id"),
194
                $daysAgo = 3650,
195
                $page = $i,
196
                $pageSize = 999,
197
                $sortByField = "Email",
198
                $sortDirection = "ASC"
199
            );
200
            if (isset($list->NumberOfPages) && $list->NumberOfPages) {
201
                if ($i > $list->NumberOfPages) {
0 ignored issues
show
Bug introduced by
The property NumberOfPages does not seem to exist in CS_REST_Wrapper_Result.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
202
                    $i = 999999;
203
                }
204
            }
205
            if (isset($list->Results)) {
206
                foreach ($list->Results as $obj) {
0 ignored issues
show
Bug introduced by
The property Results does not seem to exist in CS_REST_Wrapper_Result.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
207
                    $this->previouslyBouncedSubscribers[$obj->EmailAddress] = true;
208
                }
209
            } else {
210
                return;
211
            }
212
        }
213
    }
214
215
    /**
216
     * updates previouslyUnsubscribedSubscribers variable
217
     *
218
     * @return null
219
     */
220 View Code Duplication
    private function getUnsubscribedSubscribers()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
221
    {
222
        $array = array();
0 ignored issues
show
Unused Code introduced by
$array 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...
223
        $api = $this->getAPI();
224
        for ($i = 1; $i < 100; $i++) {
225
            $list = $api->getUnsubscribedSubscribers(
226
                $listID = Config::inst()->get("CampaignMonitorSyncAllMembers", "mailing_list_id"),
227
                $daysAgo = 3650,
228
                $page = $i,
229
                $pageSize = 999,
230
                $sortByField = "Email",
231
                $sortDirection = "ASC"
232
            );
233
            if (isset($list->NumberOfPages) && $list->NumberOfPages) {
234
                if ($i > $list->NumberOfPages) {
0 ignored issues
show
Bug introduced by
The property NumberOfPages does not seem to exist in CS_REST_Wrapper_Result.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
235
                    $i = 999999;
236
                }
237
            }
238
            if (isset($list->Results)) {
239
                foreach ($list->Results as $obj) {
0 ignored issues
show
Bug introduced by
The property Results does not seem to exist in CS_REST_Wrapper_Result.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
240
                    $this->previouslyUnsubscribedSubscribers[$obj->EmailAddress] = true;
241
                }
242
            } else {
243
                return;
244
            }
245
        }
246
    }
247
248
    /**
249
     * @param array $memberArray
250
     * @param array $customFields
251
     * @param array $unsubscribeArray
252
     *
253
     * @return null
254
     */
255
    private function exportNow($memberArray, $customFields, $unsubscribeArray)
256
    {
257
        $api = $this->getAPI();
258
        PWUpdateGetData::flush("<hr />", "deleted");
259
        if (count($memberArray)) {
260
            if (count($memberArray) == count($customFields)) {
261
                $finalCustomFields = array();
262
                foreach ($customFields as $email => $valuesArray) {
263
                    $updateDetails = false;
264
                    $alreadyListed = false;
265
                    if (isset($this->previouslyExported[$email])) {
266
                        $alreadyListed = true;
267
                        DB::alteration_message("".$email." is already listed");
268
                        foreach ($valuesArray as $key => $value) {
269
                            if ($key != "Email") {
270
                                if (!isset($this->previouslyExported[$email][$key])) {
271
                                    if ($value == "tba" || $value == "No" || strlen(trim($value)) < 1) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
272
                                        //do nothing
273
                                    } else {
274
                                        $updateDetails = true;
275
                                        DB::alteration_message(" - - - Missing value for $key - current value $value", "created");
276
                                    }
277
                                } elseif ($this->previouslyExported[$email][$key] != $value) {
278
                                    DB::alteration_message(" - - - Update for ".$email." for $key $value that is not the same as previous value: ".$this->previouslyExported[$email][$key], "created");
279
                                    $updateDetails = true;
280
                                }
281
                            }
282
                        }
283
                    } else {
284
                        DB::alteration_message("Adding entry: ".implode("; ", $customFields[$email]).".", "created");
285
                    }
286
                    $finalCustomFields[$email] = array();
287
                    $k = 0;
288
                    foreach ($valuesArray as $key => $value) {
289
                        $finalCustomFields[$email][$k]["Key"] = $key;
290
                        $finalCustomFields[$email][$k]["Value"] = $value;
291
                        $k++;
292
                    }
293
                    if ($updateDetails) {
294
                        if (!$this->debug) {
295
                            $api->updateSubscriber(
296
                                $listID = Config::inst()->get("CampaignMonitorSyncAllMembers", "mailing_list_id"),
297
                                $oldEmailAddress = $email,
298
                                $memberArray[$email],
299
                                $finalCustomFields[$email],
300
                                $resubscribe = true,
301
                                $restartSubscriptionBasedAutoResponders = false
302
                            );
303
                        }
304
                        unset($finalCustomFields[$email]);
305
                        unset($customFields[$email]);
306
                        unset($memberArray[$email]);
307
                    } elseif ($alreadyListed) {
308
                        unset($finalCustomFields[$email]);
309
                        unset($customFields[$email]);
310
                        unset($memberArray[$email]);
311
                    }
312
                }
313
                if (count($memberArray)) {
314
                    if (count($memberArray) == count($finalCustomFields)) {
315
                        DB::alteration_message("<h3>adding: ".count($memberArray)." subscribers</h3>", "created");
316
                        if (!$this->debug) {
317
                            $api->addSubscribers(Config::inst()->get("CampaignMonitorSyncAllMembers", "mailing_list_id"), $memberArray, $finalCustomFields, true, false, false);
318
                        }
319 View Code Duplication
                    } else {
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...
320
                        DB::alteration_message("Error, memberArray (".count($memberArray).") count is not the same as finalCustomFields (".count($finalCustomFields).") count.", "deleted");
321
                    }
322
                } else {
323
                    DB::alteration_message("adding: ".count($memberArray)." subscribers");
324
                }
325
                foreach ($unsubscribeArray as $email => $member) {
326
                    DB::alteration_message("Now doing Blacklisting: ".$member->Email, "deleted");
327
                    if (!$this->debug) {
328
                        $api->unsubscribeSubscriber(Config::inst()->get("CampaignMonitorSyncAllMembers", "mailing_list_id"), $member);
329
                    }
330
                }
331 View Code Duplication
            } else {
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...
332
                DB::alteration_message("Error, memberArray (".count($memberArray).") count is not the same as customFields (".count($customFields).") count.", "deleted");
333
            }
334
        } else {
335
            DB::alteration_message("adding: ".count($memberArray)." subscribers");
336
        }
337
    }
338
}
339