Passed
Push — master ( 11319f...d27303 )
by Sergey
02:38
created

SeoManagerTrait   F

Complexity

Total Complexity 60

Size/Duplication

Total Lines 333
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 60
eloc 154
dl 0
loc 333
rs 3.6
c 0
b 0
f 0

15 Methods

Rating   Name   Duplication   Size   Complexity  
A getCleanColumns() 0 3 1
A getParamsFromURI() 0 5 1
A isParam() 0 8 2
A isTitle() 0 8 2
A importRoutes() 0 19 3
A cleanFilePath() 0 3 1
A getAllModels() 0 20 5
A getColumns() 0 9 2
A __construct() 0 4 1
A cleanParam() 0 3 1
A cleanRoutes() 0 12 4
B getDynamicTitle() 0 31 8
F getMetaData() 0 48 14
C getOgData() 0 30 12
A getMappedValue() 0 17 3

How to fix   Complexity   

Complex Class

Complex classes like SeoManagerTrait 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.

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

1
<?php
2
/**
3
 * Created by PhpStorm.
4
 * User: sergeykarakhanyan
5
 * Date: 10/30/18
6
 * Time: 12:00
7
 */
8
9
namespace Lionix\SeoManager\Traits;
10
11
use Illuminate\Support\Facades\File;
12
use Lionix\SeoManager\Models\SeoManager;
13
use Illuminate\Support\Facades\Schema;
14
15
trait SeoManagerTrait
16
{
17
    protected $exceptRoutes = [
18
        'api',
19
        'telescope',
20
        '_debugbar'
21
    ];
22
23
    protected $exceptColumns = [
24
        "password",
25
        "remember_token",
26
    ];
27
28
    public function __construct()
29
    {
30
        $this->exceptRoutes = array_merge($this->exceptRoutes, config('seo-manager.except_routes'));
0 ignored issues
show
Bug introduced by
The function config was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

30
        $this->exceptRoutes = array_merge($this->exceptRoutes, /** @scrutinizer ignore-call */ config('seo-manager.except_routes'));
Loading history...
31
        $this->exceptColumns = array_merge($this->exceptColumns, config('seo-manager.except_columns'));
32
    }
33
34
    /**
35
     * Detect Parameters from the URI
36
     * @param $uri
37
     * @return mixed
38
     */
39
    private function getParamsFromURI($uri)
40
    {
41
        preg_match_all('/{(.*?)}/', $uri, $output_array);
42
43
        return $output_array[1];
44
    }
45
46
    /**
47
     * Check if the given data is URI param
48
     * @param $param
49
     * @return bool
50
     */
51
    private function isParam($param)
52
    {
53
        $pattern_params = '/{(.*?)}/';
54
        preg_match_all($pattern_params, $param, $output_params);
55
        if (!empty($output_params[1])) {
56
            return true;
57
        }
58
        return false;
59
    }
60
61
    /**
62
     * Check if the given data is Title
63
     * @param $param
64
     * @return bool
65
     */
66
    private function isTitle($param)
67
    {
68
        $pattern_title = '/~(.*?)~/';
69
        preg_match_all($pattern_title, $param, $pattern_title);
70
        if (!empty($pattern_title[1])) {
71
            return true;
72
        }
73
        return false;
74
    }
75
76
    /**
77
     * Remove unnecessary characters from param
78
     * @param $param
79
     * @return string
80
     */
81
    private function cleanParam($param)
82
    {
83
        return strtolower(str_replace(['{', '}'], '', $param));
84
    }
85
86
    /**
87
     * Remove routes which shouldn't be imported to Seo Manager
88
     * @return array
89
     */
90
    private function cleanRoutes()
91
    {
92
        $routes = \Route::getRoutes();
93
        $getRoutes = array_keys($routes->get('GET'));
94
        foreach ($getRoutes as $key => $route) {
95
            foreach ($this->exceptRoutes as $rule) {
96
                if (strpos($route, $rule) !== FALSE) {
97
                    unset($getRoutes[$key]);
98
                }
99
            }
100
        }
101
        return $getRoutes;
102
    }
103
104
    /**
105
     * @return array
106
     * @throws \ReflectionException
107
     */
108
    private function getAllModels()
109
    {
110
        $path = base_path('app') . '/' . config('seo-manager.models_path');
0 ignored issues
show
Bug introduced by
The function config was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

110
        $path = base_path('app') . '/' . /** @scrutinizer ignore-call */ config('seo-manager.models_path');
Loading history...
Bug introduced by
The function base_path was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

110
        $path = /** @scrutinizer ignore-call */ base_path('app') . '/' . config('seo-manager.models_path');
Loading history...
111
112
        $models = File::allFiles($path);
113
        $cleanModelNames = [];
114
        foreach ($models as $model) {
115
            $modelPath = $this->cleanFilePath($model);
116
            $reflectionClass =(new \ReflectionClass($modelPath))->getParentClass();
117
            if($reflectionClass !== false){
118
                if($reflectionClass->getName() === "Illuminate\Database\Eloquent\Model" || $reflectionClass->getName() === "Illuminate\Foundation\Auth\User"){
119
                    $cleanModel = [
120
                        'path' => $modelPath,
121
                        'name' => str_replace('.php', '', $model->getFilename())
122
                    ];
123
                    array_push($cleanModelNames, $cleanModel);
124
                }
125
            }
126
        }
127
        return $cleanModelNames;
128
    }
129
130
    /**
131
     * Get Model all Columns
132
     * @param $model
133
     * @return array
134
     */
135
    public function getColumns($model)
136
    {
137
        $appends = [];
138
        if (method_exists((new $model), 'getAppends')) {
139
            $appends = (new $model)->getAppends();
140
        }
141
        $table = (new $model)->getTable();
142
        $columns = $this->getCleanColumns(Schema::getColumnListing($table));
143
        return array_merge($columns, $appends);
144
    }
145
146
    /**
147
     * Clean model file path
148
     * @param $file
149
     * @return string
150
     */
151
    private function cleanFilePath($file)
152
    {
153
        return '\\' . ucfirst(str_replace('/', '\\', substr($file, strpos($file, 'app'), -4)));
154
    }
155
156
    /**
157
     * Remove unnecessary columns from table columns list
158
     * @param $columns
159
     * @return array
160
     */
161
    private function getCleanColumns($columns)
162
    {
163
        return array_diff($columns, $this->exceptColumns);
164
    }
165
166
    /**
167
     * Import Routes to SeoManager database
168
     * @return array|\Illuminate\Database\Eloquent\Collection|static[]
0 ignored issues
show
Bug introduced by
The type Illuminate\Database\Eloquent\Collection 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...
169
     */
170
    private function importRoutes()
171
    {
172
        $routes = $this->cleanRoutes();
173
        foreach ($routes as $uri) {
174
            $data = [
175
                'uri' => $uri,
176
                'params' => $this->getParamsFromURI($uri),
177
                'keywords' => [],
178
                'title_dynamic' => []
179
            ];
180
            if (!SeoManager::where('uri', $uri)->first()) {
181
                $seoManager = new SeoManager();
182
                $seoManager->fill($data);
183
                $seoManager->save();
184
            }
185
        }
186
187
        $routes = SeoManager::all();
188
        return $routes;
189
    }
190
191
    /**
192
     * Get mapped Seo Data from Database for Current Route
193
     * @param $property
194
     * @return mixed
195
     */
196
    private function getMetaData($property)
197
    {
198
        $route = \Route::current();
199
        $uri = $route->uri();
200
        $seoManager = SeoManager::where('uri', $uri)->first();
201
        if(is_null($seoManager)){
202
            return null;
203
        }
204
        $metaData = [];
205
        if(count($seoManager->keywords) > 0){
206
            $metaData['keywords'] = implode(', ', $seoManager->keywords);
207
        }
208
        if($seoManager->description){
209
            $metaData['description'] = $seoManager->description;
210
        }
211
        if($seoManager->title){
212
            $metaData['title'] = $seoManager->title;
213
        }
214
        if($seoManager->url){
215
            $metaData['url'] = $seoManager->url;
216
        }else{
217
            $metaData['url'] = url()->full();
0 ignored issues
show
Bug introduced by
The function url was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

217
            $metaData['url'] = /** @scrutinizer ignore-call */ url()->full();
Loading history...
218
        }
219
        if($seoManager->author){
220
            $metaData['author'] = $seoManager->author;
221
        }
222
        if ($seoManager->mapping !== null) {
223
            $metaData['title_dynamic'] = $this->getDynamicTitle($seoManager->title_dynamic, $seoManager, $route->parameters);
224
        }
225
        if ($seoManager->og_data) {
226
            $ogData = $this->getOgData($seoManager, $route->parameters);
227
            if($property === 'og_data'){
228
                $metaData['og_data'] = $ogData;
229
            }else{
230
                foreach ($ogData as $key => $og) {
231
                    $metaData[$key] = $og;
232
                }
233
            }
234
        }
235
236
        if($property !== null && !empty($property)){
237
            if(isset($metaData[$property])){
238
                return $metaData[$property];
239
            }else{
240
                return null;
241
            }
242
        }
243
        return $metaData;
244
    }
245
246
    /**
247
     * Get dynamic title based on user configs for current route
248
     * @param $params
249
     * @param $manager
250
     * @param $routeParams
251
     * @return string
252
     */
253
    private function getDynamicTitle($params, $manager, $routeParams = null)
254
    {
255
        $dynamicTitle = '';
256
        if(is_array($params)){
257
            foreach ($params as $param) {
258
                if ($this->isParam($param)) {
259
                    $param = $this->cleanParam($param);
260
                    $paramsArray = explode('-', $param);
261
                    $mapping = $manager->mapping[$paramsArray[0]];
262
                    $model = $mapping['model']['path'];
263
                    $findBy = $mapping['find_by'];
264
                    $selectedColumns = $mapping['selectedColumns'];
265
                    if (in_array($paramsArray[1], $selectedColumns)) {
266
                        $mappedTitle = (new $model);
267
                        if ($routeParams) {
268
                            $mappedTitle = $mappedTitle->where($findBy, $routeParams[$paramsArray[0]])->first();
269
                        } else {
270
                            $mappedTitle = $mappedTitle->first();
271
                        }
272
                        if ($mappedTitle) {
273
                            $dynamicTitle .= optional($mappedTitle)->{$paramsArray[1]} . ' ';
274
                        }
275
                    }
276
                } elseif ($this->isTitle($param)) {
277
                    $dynamicTitle .= $manager->title . ' ';
278
                } else {
279
                    $dynamicTitle .= $param . ' ';
280
                }
281
            }
282
        }
283
        return $dynamicTitle;
284
    }
285
286
    /**
287
     * Get Open Graph Dynamic Data
288
     * @param $seoManager
289
     * @param $routeParams
290
     * @return array
291
     */
292
    private function getOgData($seoManager, $routeParams)
293
    {
294
        $dataArray = [];
295
        $value = '';
296
        foreach ($seoManager->og_data as $key => $og) {
297
            if (is_array(reset($og['data']))) {
298
                foreach ($og['data'] as $ogKey => $data) {
299
                    if ($data['mapped']) {
300
                        $value = $this->getMappedValue($data['value'], $seoManager, $routeParams);
301
                    } elseif ($data['value']) {
302
                        $value = $data['value'];
303
                    }
304
                    if ($data['value']) {
305
                        $dataArray['og:' . $key . ':' . $ogKey] = $value;
306
                    }
307
                }
308
            } else {
309
                if ($og['data']['mapped']) {
310
                    $value = $this->getMappedValue($og['data']['value'], $seoManager, $routeParams);
311
                } elseif ($og['data']['value']) {
312
                    $value = $og['data']['value'];
313
                } elseif ($key === 'url') {
314
                    $value = url()->full();
0 ignored issues
show
Bug introduced by
The function url was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

314
                    $value = /** @scrutinizer ignore-call */ url()->full();
Loading history...
315
                }
316
                if ($og['data']['value'] || $key === 'url') {
317
                    $dataArray['og:' . $key] = $value;
318
                }
319
            }
320
        }
321
        return $dataArray;
322
    }
323
324
    /**
325
     * Get Open Graph Data Values based on Mapped Params
326
     * @param $value
327
     * @param $manager
328
     * @param $routeParams
329
     * @return mixed
330
     */
331
    private function getMappedValue($value, $manager, $routeParams)
332
    {
333
        $paramsArray = explode('-', strtolower($value));
334
        $mapping = $manager->mapping[$paramsArray[0]];
335
        $model = $mapping['model']['path'];
336
        $findBy = $mapping['find_by'];
337
        $selectedColumns = $mapping['selectedColumns'];
338
        $mapped = null;
339
        if (in_array($paramsArray[1], $selectedColumns)) {
340
            $mapped = (new $model);
341
            if ($routeParams) {
342
                $mapped = $mapped->where($findBy, $routeParams[$paramsArray[0]])->first();
343
            }else{
344
                $mapped = $mapped->first();
345
            }
346
        }
347
        return optional($mapped)->{$paramsArray[1]};
348
    }
349
}
350