Test Failed
Push — master ( dd0813...14557d )
by Antony
06:13
created

UnleashedUpdateProductTask::run()   F

Complexity

Conditions 23
Paths 96

Size

Total Lines 165
Code Lines 114

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 23
eloc 114
nc 96
nop 1
dl 0
loc 165
rs 3.3333
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace AntonyThorpe\SilverShopUnleashed;
4
5
use Psr\Http\Message\ResponseInterface;
6
use GuzzleHttp\Exception\RequestException;
7
use DateTime;
8
use DateTimeZone;
9
use SilverStripe\Core\Convert;
10
use SilverStripe\Dev\Debug;
11
use SilverStripe\Control\Email\Email;
12
use SilverShop\Page\Product;
13
use SilverShop\Page\ProductCategory;
14
use SilverShop\Extension\ShopConfigExtension;
15
use AntonyThorpe\Consumer\Consumer;
16
use AntonyThorpe\Consumer\Utilities;
17
18
/**
19
 * Update Products with fresh data from Unleashed Inventory Management Software
20
 *
21
 * @package silvershop-unleashed
22
 * @subpackage tasks
23
 */
24
25
abstract class UnleashedUpdateProductTask extends UnleashedBuildTask
26
{
27
    /**
28
     * @var string
29
     */
30
    protected $title = "Unleashed: Update Products";
31
32
    /**
33
     * @var string
34
     */
35
    protected $description = "Update the Products in Silvershop with data from Unleashed.  Will not automatically bring over new items but will update Titles, Base Price, etc.";
36
37
    protected $email_subject = "API Unleashed Software - Update Product Results";
38
39
    public function run($request)
40
    {
41
        // Definitions
42
        $config = $this->config();
0 ignored issues
show
Unused Code introduced by
The assignment to $config is dead and can be removed.
Loading history...
43
        $silvershopInternalItemIDMustBeUnique = Product::get()->column('InternalItemID');
44
        $silvershopTitleMustBeUnique = Product::get()->column('Title');
45
        $consumer = Consumer::get()->find('Title', 'ProductUpdate');
46
47
        // Get Products from Unleashed
48
        if (!$consumer) {
0 ignored issues
show
introduced by
$consumer is of type SilverStripe\ORM\DataObject, thus it always evaluated to true.
Loading history...
49
            $response = UnleashedAPI::sendCall(
50
                'GET',
51
                'https://api.unleashedsoftware.com/Products'
52
            );
53
54
            $apidata_array = json_decode($response->getBody()->getContents(), true);
55
            $apidata = $apidata_array['Items'];
56
            $pagination = $apidata_array['Pagination'];
57
            $numberofpages = (int) $pagination['NumberOfPages'];
58
59
            if ($numberofpages > 1) {
60
                for ($i = 2; $i <= $numberofpages; $i++) {
61
                    $response = UnleashedAPI::sendCall(
62
                        'GET',
63
                        'https://api.unleashedsoftware.com/Products/' . $i
64
                    );
65
                    $apidata_array = json_decode($response->getBody()->getContents(), true);
66
                    $apidata = array_merge($apidata, $apidata_array['Items']);
67
                }
68
            }
69
        } else {
70
            $query = [];
71
            $date = new DateTime($consumer->ExternalLastEdited);
72
            $date->setTimezone(new DateTimeZone("UTC"));  // required for Unleashed Products (not for other endpoints)
73
            $query['modifiedSince'] = substr($date->format('Y-m-d\TH:i:s.u'), 0, 23);
74
75
            $response = UnleashedAPI::sendCall(
76
                'GET',
77
                'https://api.unleashedsoftware.com/Products',
78
                ['query' => $query]
79
            );
80
81
            $apidata_array = json_decode($response->getBody()->getContents(), true);
82
            $apidata = $apidata_array['Items'];
83
            $pagination = $apidata_array['Pagination'];
84
            $numberofpages = (int) $pagination['NumberOfPages'];
85
86
            if ($numberofpages > 1) {
87
                for ($i = 2; $i <= $numberofpages; $i++) {
88
                    $response = UnleashedAPI::sendCall(
89
                        'GET',
90
                        'https://api.unleashedsoftware.com/Products/' . $i,
91
                        ['query' => $query]
92
                    );
93
                    $apidata_array = json_decode($response->getBody()->getContents(), true);
94
                    $apidata = array_merge($apidata, $apidata_array['Items']);
95
                }
96
            }
97
            var_dump($apidata);
0 ignored issues
show
Security Debugging Code introduced by
var_dump($apidata) looks like debug code. Are you sure you do not want to remove it?
Loading history...
98
        }
99
100
        $this->log('<h2>Preliminary Checks</h2>');
101
        // Check for duplicates in DataList before proceeding further
102
        $duplicates = Utilities::getDuplicates($silvershopInternalItemIDMustBeUnique);
103
        if (!empty($duplicates)) {
104
            echo "<h2>Duplicate check of Product InternalItemID within Silvershop</h2>";
105
            foreach ($duplicates as $duplicate) {
106
                $this->log($duplicate);
107
            }
108
            $this->log('Please remove duplicates from Silvershop before running this Build Task');
109
            $this->log('Exit');
110
            die();
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
111
        } else {
112
            $this->log('No duplicate found');
113
        }
114
115
        $duplicates = Utilities::getDuplicates($silvershopTitleMustBeUnique);
116
        if (!empty($duplicates)) {
117
            echo "<h2>Duplicate check of Product Titles within Silvershop</h2>";
118
            foreach ($duplicates as $duplicate) {
119
                $this->log($duplicate);
120
            }
121
            $this->log('Please remove duplicates from Silvershop before running this Build Task');
122
            $this->log('Exit');
123
            die();
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
124
        } else {
125
            $this->log('No duplicate found');
126
        }
127
128
        // Check for duplicates in apidata before proceeding further
129
        $duplicates = Utilities::getDuplicates(array_column($apidata, 'ProductCode'));
130
        if ($duplicates) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $duplicates of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
131
            echo "<h2>Duplicate check of ProductCode within Unleashed</h2>";
132
            foreach ($duplicates as $duplicate) {
133
                $this->log(htmlspecialchars($duplicate, ENT_QUOTES, 'utf-8'));
134
            }
135
            $this->log(
136
                'Please remove duplicates from Unleashed before running this Build Task'
137
            );
138
            $this->log('Exit');
139
            die();
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
140
        } else {
141
            $this->log('No duplicate found');
142
        }
143
144
        // Update
145
        $this->log('<h3>Update Product records in Silvershop</h3>');
146
        $loader = ProductBulkLoader::create('SilverShop\Page\Product');
147
        $loader->transforms = [
148
            'Parent' => [
149
                'callback' => function ($value, $placeholder) {
0 ignored issues
show
Unused Code introduced by
The parameter $placeholder is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

149
                'callback' => function ($value, /** @scrutinizer ignore-unused */ $placeholder) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
150
                    $obj = ProductCategory::get()->find('Guid', $value['Guid']);
151
                    if ($obj) {
152
                        return $obj;
153
                    } else {
154
                        return ProductCategory::get()->find('Title', $value['GroupName']);
155
                    }
156
                }
157
            ],
158
            'BasePrice' => [
159
                'callback' => function ($value, $placeholder) {
0 ignored issues
show
Unused Code introduced by
The parameter $placeholder is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

159
                'callback' => function ($value, /** @scrutinizer ignore-unused */ $placeholder) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
160
                    return (float)$value;
161
                }
162
            ],
163
            'Title' => [
164
                'callback' => function ($value, &$placeholder) {
165
                    $placeholder->URLSegment = Convert::raw2url($value);
166
                    return $value;
167
                }
168
            ]
169
        ];
170
        $results = $loader->updateRecords($apidata, $this->preview);
171
172
        if ($results->UpdatedCount()) {
173
            $this->log(Debug::text($results->getData()));
174
        }
175
        $this->log("Done");
176
        Debug::show($results->Count());
177
        Debug::show(!$this->preview);
178
        Debug::show(Email::config()->admin_email);
179
        Debug::show($this->email_subject);
180
        // Send email
181
        if ($results->Count() && !$this->preview && Email::config()->admin_email && $this->email_subject) {
182
            // send email
183
            $email = Email::create(
184
                ShopConfigExtension::config()->email_from ? ShopConfigExtension::config()->email_from : Email::config()->admin_email,
185
                Email::config()->admin_email,
186
                $this->email_subject,
187
                Debug::text($results->getData())
188
            );
189
            $dispatched = $email->send();
190
            if ($dispatched) {
191
                $this->log('Email sent');
192
            }
193
        }
194
195
        if (!$this->preview && $apidata) {
196
            if (!$consumer) {
0 ignored issues
show
introduced by
$consumer is of type SilverStripe\ORM\DataObject, thus it always evaluated to true.
Loading history...
197
                $consumer = Consumer::create([
198
                    'Title' => 'ProductUpdate',
199
                    'ExternalLastEditedKey' => 'LastModifiedOn'
200
                ]);
201
            }
202
            $consumer->setMaxExternalLastEdited($apidata);
203
            $consumer->write();
204
        }
205
    }
206
}
207