Passed
Push — develop ( 32f3a3...a88678 )
by Andrew
08:35
created

ContentSeoController::actionMetaBundles()   F

Complexity

Conditions 23
Paths 273

Size

Total Lines 150
Code Lines 101

Duplication

Lines 0
Ratio 0 %

Importance

Changes 14
Bugs 0 Features 0
Metric Value
cc 23
eloc 101
c 14
b 0
f 0
nc 273
nop 5
dl 0
loc 150
rs 1.9366

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
 * SEOmatic plugin for Craft CMS 3.x
4
 *
5
 * @link      https://nystudio107.com/
6
 * @copyright Copyright (c) 2019 nystudio107
7
 * @license   https://nystudio107.com/license
0 ignored issues
show
Coding Style introduced by
@license tag must contain a URL and a license name
Loading history...
8
 */
9
10
namespace nystudio107\seomatic\controllers;
11
12
use nystudio107\seomatic\base\SeoElementInterface;
13
use nystudio107\seomatic\models\MetaBundle;
14
use nystudio107\seomatic\Seomatic;
15
use nystudio107\seomatic\services\SeoElements;
16
17
use Craft;
18
use craft\db\Query;
19
use craft\helpers\UrlHelper;
20
use craft\web\Controller;
21
22
use yii\web\BadRequestHttpException;
23
use yii\web\Response;
24
25
/**
26
 * @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...
27
 * @package   Seomatic
28
 * @since     3.2.18
29
 */
30
class ContentSeoController extends Controller
31
{
32
    // Constants
33
    // =========================================================================
34
35
    const SORT_MAP = [
36
        'DESC' => SORT_DESC,
37
        'ASC' => SORT_ASC,
38
    ];
39
40
    const ALLOWED_SORT_FIELDS = [
41
        'sourceName',
42
        'sourceType',
43
    ];
44
45
    // Protected Properties
46
    // =========================================================================
47
48
    /**
49
     * @var    bool|array
50
     */
51
    protected $allowAnonymous = [
52
    ];
53
54
    // Public Methods
55
    // =========================================================================
56
57
    /**
58
     * Handle requests for the dashboard statistics table
59
     *
60
     * @param string   $sort
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
61
     * @param int      $page
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
62
     * @param int      $per_page
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
63
     * @param string   $filter
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
64
     * @param null|int $siteId
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
65
     *
66
     * @return Response
67
     * @throws BadRequestHttpException
68
     */
69
    public function actionMetaBundles(
70
        string $sort = 'sourceName|asc',
71
        int $page = 1,
72
        int $per_page = 20,
73
        $filter = '',
74
        $siteId = 0
75
    ): Response {
76
        $data = [];
77
        $sortField = 'sourceName';
78
        $sortType = 'ASC';
79
        // Figure out the sorting type
80
        if ($sort !== '') {
81
            if (strpos($sort, '|') === false) {
82
                $sortField = $sort;
83
            } else {
84
                list($sortField, $sortType) = explode('|', $sort);
85
            }
86
        }
87
        $sortType = strtoupper($sortType);
88
        $sortType = self::SORT_MAP[$sortType] ?? self::SORT_MAP['DESC'];
89
        $sortParams = [
90
            $sortField => $sortType,
91
        ];
92
        // Validate untrusted data
93
        if (!in_array($sortField, self::ALLOWED_SORT_FIELDS, true)) {
94
            throw new BadRequestHttpException(Craft::t('seomatic', 'Invalid sort field specified.'));
95
        }
96
        if ($sortField !== 'sourceName') {
97
            $sortParams = array_merge($sortParams, [
98
                'sourceName' => self::SORT_MAP['ASC'],
99
            ]);
100
        }
101
102
        // Query the db table
103
        $offset = ($page - 1) * $per_page;
104
105
        $currentSiteHandle = '';
106
        if ((int)$siteId !== 0) {
107
            $site = Craft::$app->getSites()->getSiteById($siteId);
0 ignored issues
show
Bug introduced by
It seems like $siteId can also be of type null; however, parameter $siteId of craft\services\Sites::getSiteById() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

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

107
            $site = Craft::$app->getSites()->getSiteById(/** @scrutinizer ignore-type */ $siteId);
Loading history...
108
            if ($site !== null) {
109
                $currentSiteHandle = $site->handle;
110
            }
111
        }
112
        $bundleQuery = (new Query())
113
            ->select(['mb.*'])
114
            ->offset($offset)
115
            ->limit($per_page)
116
            ->orderBy($sortParams)
0 ignored issues
show
Coding Style introduced by
Space after closing parenthesis of function call prohibited
Loading history...
117
            ;
118
119
        // Since sectionIds, CategoryIds, etc. are not unique, we need to special case for them
120
        $seoElements = Seomatic::$plugin->seoElements->getAllSeoElementTypes();
121
        $tableIndex = 1;
122
        foreach ($seoElements as $seoElement) {
123
            $tableIndex++;
124
            $subQuery = (new Query())
125
                ->from(['{{%seomatic_metabundles}}'])
126
                ->where(['=', 'sourceBundleType', $seoElement::META_BUNDLE_TYPE]);
0 ignored issues
show
Bug introduced by
The constant nystudio107\seomatic\bas...rface::META_BUNDLE_TYPE was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
127
            if ((int)$siteId !== 0) {
128
                $subQuery->andWhere(['sourceSiteId' => $siteId]);
129
            }
130
            if ($filter !== '') {
131
                $subQuery->andWhere(['like', 'sourceName', $filter]);
132
            }
133
            $bundleQuery
134
                ->where(['mb'.$tableIndex.'.id' => null])
135
                ->from(['mb' => $subQuery])
136
                ->leftJoin(['mb'.$tableIndex => $subQuery], [
137
                    'and',
138
                    '[[mb.sourceId]] = [[mb'.$tableIndex.'.sourceId]]',
139
                    '[[mb.id]] < [[mb'.$tableIndex.'.id]]'
140
                ]);
141
        }
142
        $bundles = $bundleQuery->all();
143
        if ($bundles) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $bundles 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...
144
            $dataArray = [];
145
            // Add in the `addLink` field
146
            foreach ($bundles as $bundle) {
147
                $dataItem = [];
148
                $metaBundle = MetaBundle::create($bundle);
149
                if ($metaBundle !== null) {
150
                    $sourceBundleType = $metaBundle->sourceBundleType;
151
                    $sourceHandle = $metaBundle->sourceHandle;
152
                    // For all the emojis
153
                    $dataItem['sourceName'] = html_entity_decode($metaBundle->sourceName, ENT_NOQUOTES, 'UTF-8');
154
                    $dataItem['sourceType'] = $metaBundle->sourceType;
155
                    $dataItem['contentSeoUrl'] = UrlHelper::cpUrl(
156
                        "seomatic/edit-content/general/{$sourceBundleType}/{$sourceHandle}/{$currentSiteHandle}"
157
                    );
158
                    // Fill in the number of entries
159
                    $entries = 0;
160
                    $seoElement = null;
161
                    if ($metaBundle->sourceBundleType) {
162
                        $seoElement = Seomatic::$plugin->seoElements->getSeoElementByMetaBundleType(
163
                            $metaBundle->sourceBundleType
164
                        );
165
                    }
166
                    /** @var SeoElementInterface $seoElement */
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
The close comment tag must be the only content on the line
Loading history...
167
                    if ($seoElement !== null) {
168
                        // Ensure `null` so that the resulting element query is correct
169
                        if (empty($metaBundle->metaSitemapVars->sitemapLimit)) {
170
                            $metaBundle->metaSitemapVars->sitemapLimit = null;
171
                        }
172
                        $query = $seoElement::sitemapElementsQuery($metaBundle);
173
                        $entries = $query->count();
174
                    }
175
                    $dataItem['entries'] = $entries;
176
                    // Basic configuration setup
177
                    $dataItem['title'] = $metaBundle->metaGlobalVars->seoTitle !== '' ? 'enabled' : 'disabled';
178
                    $dataItem['description'] = $metaBundle->metaGlobalVars->seoDescription !== '' ? 'enabled' : 'disabled';
179
                    $dataItem['image'] = $metaBundle->metaGlobalVars->seoImage !== '' ? 'enabled' : 'disabled';
180
                    $dataItem['sitemap'] = $metaBundle->metaSitemapVars->sitemapUrls ? 'enabled' : 'disabled';
181
                    $dataItem['robots'] = $metaBundle->metaGlobalVars->robots;
182
                    // Calculate the setup stat
183
                    $stat = 0;
184
                    $numGrades = \count(SettingsController::SETUP_GRADES);
185
                    $numFields = \count(SettingsController::SEO_SETUP_FIELDS);
186
                    foreach (SettingsController::SEO_SETUP_FIELDS as $setupField => $setupLabel) {
187
                        $stat += (int)!empty($metaBundle->metaGlobalVars[$setupField]);
188
                        $value = $variables['contentSetupChecklist'][$setupField]['value'] ?? 0;
189
                        $variables['contentSetupChecklist'][$setupField] = [
190
                            'label' => $setupLabel,
191
                            'value' => $value + (int)!empty($metaBundle->metaGlobalVars[$setupField]),
192
                        ];
193
                    }
194
                    $stat = round($numGrades - (($stat * $numGrades) / $numFields));
195
                    if ($stat >= $numGrades) {
196
                        $stat = $numGrades - 1;
197
                    }
198
                    $dataItem['setup'] = SettingsController::SETUP_GRADES[$stat];
199
200
                    $dataArray[] = $dataItem;
201
                }
202
            }
203
            // Format the data for the API
204
            $data['data'] = $dataArray;
205
            $count = $bundleQuery->count();
206
            $data['links']['pagination'] = [
207
                'total' => $count,
208
                'per_page' => $per_page,
209
                'current_page' => $page,
210
                'last_page' => ceil($count / $per_page),
211
                'next_page_url' => null,
212
                'prev_page_url' => null,
213
                'from' => $offset + 1,
214
                'to' => $offset + ($count > $per_page ? $per_page : $count),
215
            ];
216
        }
217
218
        return $this->asJson($data);
219
    }
220
221
    // Protected Methods
222
    // =========================================================================
223
}
224