Passed
Push — master ( c642f0...b88e34 )
by Antony
07:52
created

UnleashedUpdateProductTask::run()   F

Complexity

Conditions 23
Paths 96

Size

Total Lines 163
Code Lines 112

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 23
eloc 112
nc 96
nop 1
dl 0
loc 163
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\Task;
4
5
use AntonyThorpe\Consumer\Consumer;
6
use AntonyThorpe\Consumer\Utilities;
7
use AntonyThorpe\SilverShopUnleashed\Task\UnleashedBuildTask;
8
use AntonyThorpe\SilverShopUnleashed\UnleashedAPI;
9
use DateTime;
10
use DateTimeZone;
11
use GuzzleHttp\Exception\RequestException;
12
use Psr\Http\Message\ResponseInterface;
13
use SilverShop\Extension\ShopConfigExtension;
14
use SilverShop\Page\Product;
15
use SilverShop\Page\ProductCategory;
16
use SilverStripe\Control\Email\Email;
17
use SilverStripe\Core\Convert;
18
use SilverStripe\Dev\Debug;
19
20
/**
21
 * Update Products with fresh data from Unleashed Inventory Management Software
22
 */
23
abstract class UnleashedUpdateProductTask extends UnleashedBuildTask
24
{
25
    /**
26
     * @var string
27
     */
28
    protected $title = "Unleashed: Update Products";
29
30
    /**
31
     * @var string
32
     */
33
    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.";
34
35
    protected $email_subject = "API Unleashed Software - Update Product Results";
36
37
    public function run($request)
38
    {
39
        // Definitions
40
        $silvershopInternalItemIDMustBeUnique = Product::get()->column('InternalItemID');
41
        $silvershopTitleMustBeUnique = Product::get()->column('Title');
42
        $consumer = Consumer::get()->find('Title', 'ProductUpdate');
43
44
        // Get Products from Unleashed
45
        if (!$consumer) {
0 ignored issues
show
introduced by
$consumer is of type SilverStripe\ORM\DataObject, thus it always evaluated to true.
Loading history...
46
            $response = UnleashedAPI::sendCall(
47
                'GET',
48
                'https://api.unleashedsoftware.com/Products'
49
            );
50
51
            $apidata_array = json_decode($response->getBody()->getContents(), true);
52
            $apidata = $apidata_array['Items'];
53
            $pagination = $apidata_array['Pagination'];
54
            $numberofpages = (int) $pagination['NumberOfPages'];
55
56
            if ($numberofpages > 1) {
57
                for ($i = 2; $i <= $numberofpages; $i++) {
58
                    $response = UnleashedAPI::sendCall(
59
                        'GET',
60
                        'https://api.unleashedsoftware.com/Products/' . $i
61
                    );
62
                    $apidata_array = json_decode($response->getBody()->getContents(), true);
63
                    $apidata = array_merge($apidata, $apidata_array['Items']);
64
                }
65
            }
66
        } else {
67
            $query = [];
68
            $date = new DateTime($consumer->ExternalLastEdited);
69
            $date->setTimezone(new DateTimeZone("UTC"));  // required for Unleashed Products (not for other endpoints)
70
            $query['modifiedSince'] = substr($date->format('Y-m-d\TH:i:s.u'), 0, 23);
71
72
            $response = UnleashedAPI::sendCall(
73
                'GET',
74
                'https://api.unleashedsoftware.com/Products',
75
                ['query' => $query]
76
            );
77
78
            $apidata_array = json_decode($response->getBody()->getContents(), true);
79
            $apidata = $apidata_array['Items'];
80
            $pagination = $apidata_array['Pagination'];
81
            $numberofpages = (int) $pagination['NumberOfPages'];
82
83
            if ($numberofpages > 1) {
84
                for ($i = 2; $i <= $numberofpages; $i++) {
85
                    $response = UnleashedAPI::sendCall(
86
                        'GET',
87
                        'https://api.unleashedsoftware.com/Products/' . $i,
88
                        ['query' => $query]
89
                    );
90
                    $apidata_array = json_decode($response->getBody()->getContents(), true);
91
                    $apidata = array_merge($apidata, $apidata_array['Items']);
92
                }
93
            }
94
        }
95
96
        $this->log('<h2>Preliminary Checks</h2>');
97
        // Check for duplicates in DataList before proceeding further
98
        $duplicates = Utilities::getDuplicates($silvershopInternalItemIDMustBeUnique);
99
        if (!empty($duplicates)) {
100
            echo "<h2>Duplicate check of Product InternalItemID within Silvershop</h2>";
101
            foreach ($duplicates as $duplicate) {
102
                $this->log($duplicate);
103
            }
104
            $this->log('Please remove duplicates from Silvershop before running this Build Task');
105
            $this->log('Exit');
106
            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...
107
        } else {
108
            $this->log('No duplicate found');
109
        }
110
111
        $duplicates = Utilities::getDuplicates($silvershopTitleMustBeUnique);
112
        if (!empty($duplicates)) {
113
            echo "<h2>Duplicate check of Product Titles within Silvershop</h2>";
114
            foreach ($duplicates as $duplicate) {
115
                $this->log($duplicate);
116
            }
117
            $this->log('Please remove duplicates from Silvershop before running this Build Task');
118
            $this->log('Exit');
119
            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...
120
        } else {
121
            $this->log('No duplicate found');
122
        }
123
124
        // Check for duplicates in apidata before proceeding further
125
        $duplicates = Utilities::getDuplicates(array_column($apidata, 'ProductCode'));
126
        if (!empty($duplicates)) {
127
            echo "<h2>Duplicate check of ProductCode within Unleashed</h2>";
128
            foreach ($duplicates as $duplicate) {
129
                $this->log(htmlspecialchars($duplicate, ENT_QUOTES, 'utf-8'));
130
            }
131
            $this->log(
132
                'Please remove duplicates from Unleashed before running this Build Task'
133
            );
134
            $this->log('Exit');
135
            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...
136
        } else {
137
            $this->log('No duplicate found');
138
        }
139
140
        // Update
141
        $this->log('<h3>Update Product records in Silvershop</h3>');
142
        $loader = ProductBulkLoader::create('SilverShop\Page\Product');
0 ignored issues
show
Bug introduced by
The type AntonyThorpe\SilverShopU...\Task\ProductBulkLoader was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

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