Passed
Push — v1 ( bf5890...0a561e )
by Andrew
06:24 queued 03:18
created

DataSamples::deleteDataSamplesByUrl()   A

Complexity

Conditions 3
Paths 5

Size

Total Lines 19
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 13
dl 0
loc 19
rs 9.8333
c 0
b 0
f 0
cc 3
nc 5
nop 2
1
<?php
2
/**
3
 * Webperf plugin for Craft CMS 3.x
4
 *
5
 * Monitor the performance of your webpages through real-world user timing data
6
 *
7
 * @link      https://nystudio107.com
0 ignored issues
show
Coding Style introduced by
The tag in position 1 should be the @copyright tag
Loading history...
8
 * @copyright Copyright (c) 2018 nystudio107
0 ignored issues
show
Coding Style introduced by
@copyright tag must contain a year and the name of the copyright holder
Loading history...
9
 */
0 ignored issues
show
Coding Style introduced by
PHP version not specified
Loading history...
Coding Style introduced by
Missing @category tag in file comment
Loading history...
Coding Style introduced by
Missing @package tag in file comment
Loading history...
Coding Style introduced by
Missing @author tag in file comment
Loading history...
Coding Style introduced by
Missing @license tag in file comment
Loading history...
10
11
namespace nystudio107\webperf\services;
12
13
use craft\db\Query;
0 ignored issues
show
Bug introduced by
The type craft\db\Query 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...
14
use nystudio107\webperf\Webperf;
15
use nystudio107\webperf\models\DataSample;
16
17
use Craft;
0 ignored issues
show
Bug introduced by
The type Craft 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...
18
use craft\base\Component;
0 ignored issues
show
Bug introduced by
The type craft\base\Component 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...
19
20
/**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
21
 * @author    nystudio107
0 ignored issues
show
Coding Style introduced by
The tag in position 1 should be the @package tag
Loading history...
Coding Style introduced by
Content of the @author tag must be in the form "Display Name <[email protected]>"
Loading history...
Coding Style introduced by
Tag value indented incorrectly; expected 2 spaces but found 4
Loading history...
22
 * @package   Webperf
0 ignored issues
show
Coding Style introduced by
Tag value indented incorrectly; expected 1 spaces but found 3
Loading history...
23
 * @since     1.0.0
0 ignored issues
show
Coding Style introduced by
The tag in position 3 should be the @author tag
Loading history...
Coding Style introduced by
Tag value indented incorrectly; expected 3 spaces but found 5
Loading history...
24
 */
0 ignored issues
show
Coding Style introduced by
Missing @category tag in class comment
Loading history...
Coding Style introduced by
Missing @license tag in class comment
Loading history...
Coding Style introduced by
Missing @link tag in class comment
Loading history...
25
class DataSamples extends Component
26
{
27
    // Public Methods
28
    // =========================================================================
29
30
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
31
     * @param int    $siteId
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
32
     * @param string $column
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
33
     *
34
     * @return int|string
35
     */
36
    public function totalSamples(int $siteId, string $column)
37
    {
38
        // See if a redirect exists with this source URL already
39
        $query = (new Query())
40
            ->from(['{{%webperf_data_samples}}'])
41
            ->where(['not', [$column => null]])
0 ignored issues
show
Coding Style introduced by
Space after closing parenthesis of function call prohibited
Loading history...
42
            ;
43
        if ((int)$siteId !== 0) {
44
            $query->andWhere(['siteId' => $siteId]);
45
        }
46
        return $query->count();
47
    }
48
49
    /**
50
     * Add a data sample to the webperf_data_samples table
51
     *
52
     * @param DataSample $dataSample
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
53
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
54
    public function addDataSample(DataSample $dataSample)
55
    {
56
        // Validate the model before saving it to the db
57
        if ($dataSample->validate() === false) {
58
            Craft::error(
59
                Craft::t(
60
                    'webperf',
61
                    'Error validating data sample: {errors}',
62
                    ['errors' => print_r($dataSample->getErrors(), true)]
63
                ),
64
                __METHOD__
65
            );
66
67
            return;
68
        }
69
        $isNew = true;
70
        if (!empty($dataSample->requestId)) {
71
            // See if a redirect exists with this source URL already
72
            $testSample = (new Query())
73
                ->from(['{{%webperf_data_samples}}'])
74
                ->where(['requestId' => $dataSample->requestId])
75
                ->one();
76
            // If it exists, update it rather than having duplicates
77
            if (!empty($testSample)) {
78
                $isNew = false;
79
            }
80
        }
81
        // Get the validated model attributes and save them to the db
82
        $dataSampleConfig = $dataSample->getAttributes($dataSample->fields());
83
        $db = Craft::$app->getDb();
84
        if ($isNew) {
85
            Craft::debug('Creating new data sample', __METHOD__);
86
            // Create a new record
87
            try {
88
                $db->createCommand()->insert(
89
                    '{{%webperf_data_samples}}',
90
                    $dataSampleConfig
91
                )->execute();
92
            } catch (\Exception $e) {
93
                Craft::error($e->getMessage(), __METHOD__);
94
            }
95
        } else {
96
            Craft::debug('Updating existing data sample', __METHOD__);
97
            // Update the existing record
98
            try {
99
                $db->createCommand()->update(
100
                    '{{%webperf_data_samples}}',
101
                    $dataSampleConfig,
102
                    [
103
                        'requestId' => $dataSample->requestId,
104
                    ]
105
                )->execute();
106
            } catch (\Exception $e) {
107
                Craft::error($e->getMessage(), __METHOD__);
108
            }
109
        }
110
        // Trim orphaned samples
111
        $this->trimOrphanedSamples($dataSample->requestId);
112
        // After adding the DataSample, trim the webperf_data_samples db table
113
        if (Webperf::$settings->automaticallyTrimDataSamples) {
114
            $this->trimDataSamples();
115
        }
116
    }
117
118
    /**
119
     * Delete a data sample by id
120
     *
121
     * @param int $id
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
122
     *
123
     * @return int The result
124
     */
125
    public function deleteSampleById(int $id): int
126
    {
127
        $db = Craft::$app->getDb();
128
        // Delete a row from the db table
129
        try {
130
            $result = $db->createCommand()->delete(
131
                '{{%webperf_data_samples}}',
132
                [
133
                    'id' => $id,
134
                ]
135
            )->execute();
136
        } catch (\Exception $e) {
137
            Craft::error($e->getMessage(), __METHOD__);
138
            $result = 0;
139
        }
140
141
        return $result;
142
    }
143
144
    /**
145
     * Delete data samples by URL and optionally siteId
146
     *
147
     * @param string   $url
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
148
     * @param int|null $siteId
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
149
     *
150
     * @return int
151
     */
152
    public function deleteDataSamplesByUrl(string $url, int $siteId = null): int
153
    {
154
        $db = Craft::$app->getDb();
155
        // Delete a row from the db table
156
        try {
157
            $conditions = ['url' => $url];
158
            if ($siteId !== null) {
159
                $conditions['siteId'] = $siteId;
160
            }
161
            $result = $db->createCommand()->delete(
162
                '{{%webperf_data_samples}}',
163
                $conditions
164
            )->execute();
165
        } catch (\Exception $e) {
166
            Craft::error($e->getMessage(), __METHOD__);
167
            $result = 0;
168
        }
169
170
        return $result;
171
    }
172
173
    /**
174
     * Delete data all samples optionally siteId
175
     *
176
     * @param int|null $siteId
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
177
     *
178
     * @return int
179
     */
180
    public function deleteAllDataSamples(int $siteId = null): int
181
    {
182
        $db = Craft::$app->getDb();
183
        // Delete a row from the db table
184
        try {
185
            $conditions = [];
186
            if ($siteId !== null) {
187
                $conditions['siteId'] = $siteId;
188
            }
189
            $result = $db->createCommand()->delete(
190
                '{{%webperf_data_samples}}',
191
                $conditions
192
            )->execute();
193
        } catch (\Exception $e) {
194
            Craft::error($e->getMessage(), __METHOD__);
195
            $result = 0;
196
        }
197
198
        return $result;
199
    }
200
201
    /**
202
     * Trim samples that have the placeholder in the URL, aka they never
203
     * received the Boomerang beacon
204
     *
205
     * @param int $requestId
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
206
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
207
    public function trimOrphanedSamples($requestId)
208
    {
209
        $db = Craft::$app->getDb();
210
        Craft::debug('Trimming orphaned samples', __METHOD__);
211
        // Update the existing record
212
        try {
213
            $result = $db->createCommand()->delete(
214
                '{{%webperf_data_samples}}',
215
                [
216
                    'and', ['url' => DataSample::PLACEHOLDER_URL],
217
                    ['not', ['requestId' => $requestId]],
218
                ]
219
            )->execute();
220
            Craft::debug($result, __METHOD__);
221
        } catch (\Exception $e) {
222
            Craft::error($e->getMessage(), __METHOD__);
223
        }
224
    }
225
226
    /**
227
     * Trim the webperf_data_samples db table based on the dataSamplesStoredLimit
228
     * config.php setting
229
     *
230
     * @param int|null $limit
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
231
     *
232
     * @return int
233
     */
234
    public function trimDataSamples(int $limit = null): int
235
    {
236
        $affectedRows = 0;
237
        $db = Craft::$app->getDb();
238
        $quotedTable = $db->quoteTableName('{{%webperf_data_samples}}');
239
        $limit = $limit ?? Webperf::$settings->dataSamplesStoredLimit;
240
241
        if ($limit !== null) {
0 ignored issues
show
introduced by
The condition $limit !== null is always true.
Loading history...
242
            //  https://stackoverflow.com/questions/578867/sql-query-delete-all-records-from-the-table-except-latest-n
243
            try {
244
                if ($db->getIsMysql()) {
245
                    // Handle MySQL
246
                    $affectedRows = $db->createCommand(/** @lang mysql */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
247
                        "
248
                        DELETE FROM {$quotedTable}
249
                        WHERE id NOT IN (
250
                          SELECT id
251
                          FROM (
252
                            SELECT id
253
                            FROM {$quotedTable}
254
                            ORDER BY dateUpdated DESC
255
                            LIMIT {$limit}
256
                          ) foo
257
                        )
258
                        "
259
                    )->execute();
260
                }
261
                if ($db->getIsPgsql()) {
262
                    // Handle Postgres
263
                    $affectedRows = $db->createCommand(/** @lang mysql */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
264
                        "
265
                        DELETE FROM {$quotedTable}
266
                        WHERE id NOT IN (
267
                          SELECT id
268
                          FROM (
269
                            SELECT id
270
                            FROM {$quotedTable}
271
                            ORDER BY \"dateUpdated\" DESC
272
                            LIMIT {$limit}
273
                          ) foo
274
                        )
275
                        "
276
                    )->execute();
277
                }
278
            } catch (\Exception $e) {
279
                Craft::error($e->getMessage(), __METHOD__);
280
            }
281
            Craft::info(
282
                Craft::t(
283
                    'webperf',
284
                    'Trimmed {rows} from webperf_data_samples table',
285
                    ['rows' => $affectedRows]
286
                ),
287
                __METHOD__
288
            );
289
        }
290
291
        return $affectedRows;
292
    }
293
}
294