Project   C
last analyzed

Complexity

Total Complexity 64

Size/Duplication

Total Lines 638
Duplicated Lines 1.88 %

Coupling/Cohesion

Components 1
Dependencies 0

Importance

Changes 2
Bugs 1 Features 0
Metric Value
dl 12
loc 638
rs 5.5537
c 2
b 1
f 0
wmc 64
lcom 1
cbo 0

46 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 21 3
A getFilename() 0 4 1
A setFilename() 0 6 1
C getWorkingDirectory() 12 24 9
B init() 0 50 6
A addSecurityUpdate() 0 4 1
A addAlsoAvailable() 0 4 1
A getAlsoAvailable() 0 4 1
A hasAlsoAvailable() 0 4 1
A getCore() 0 4 1
A getDatestamp() 0 4 1
A getDetails() 0 4 1
A getProjectType() 0 4 1
A setProjectType() 0 4 1
A getDevVersion() 0 4 1
A setDevVersion() 0 4 1
A getExistingMajor() 0 4 1
A getExistingVersion() 0 4 1
A getFetchStatus() 0 4 1
A setFetchStatus() 0 4 1
A getInstallType() 0 4 1
A getLatestDev() 0 4 1
A setLatestDev() 0 4 1
A getLatestVersion() 0 4 1
A setLatestVersion() 0 4 1
A getName() 0 4 1
A getProject() 0 4 1
A getProjectStatus() 0 4 1
A setProjectStatus() 0 4 1
A getReason() 0 4 1
A setReason() 0 4 1
A getRecommended() 0 4 1
A setRecommended() 0 4 1
A getReleases() 0 4 1
A setReleases() 0 4 1
A getRelease() 0 8 2
A getSecurityUpdates() 0 4 1
A setSecurityUpdates() 0 4 1
A getStatus() 0 4 1
A setStatus() 0 4 1
A getStatusUrl() 0 4 1
A setStatusUrl() 0 4 1
A getVersion() 0 4 1
A hasSecurityUpdates() 0 4 1
A setDetails() 0 12 3
A setRelease() 0 4 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Project 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. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

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

1
<?php
2
3
/**
4
 * Drush Cerbere command line tools.
5
 * Copyright (C) 2015 - Sebastien Malot <[email protected]>
6
 *
7
 * This program is free software; you can redistribute it and/or modify
8
 * it under the terms of the GNU General Public License as published by
9
 * the Free Software Foundation; either version 2 of the License, or
10
 * (at your option) any later version.
11
 *
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU General Public License along
18
 * with this program; if not, write to the Free Software Foundation, Inc.,
19
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20
 */
21
22
namespace Cerbere\Model;
23
24
/**
25
 * Class Project
26
 *
27
 * @package Cerbere\Model
28
 */
29
class Project
30
{
31
    /**
32
     * URL to check for updates, if a given project doesn't define its own.
33
     */
34
    const UPDATE_DEFAULT_URL = 'http://updates.drupal.org/release-history';
35
36
    /**
37
     *
38
     */
39
    const INSTALL_TYPE_OFFICIAL = 'official';
40
41
    /**
42
     *
43
     */
44
    const INSTALL_TYPE_DEV = 'dev';
45
46
    /**
47
     *
48
     */
49
    const INSTALL_TYPE_UNKNOWN = 'unknown';
50
51
    /**
52
     *
53
     */
54
    const TYPE_PROJECT_DISTRIBUTION = 'project_distribution';
55
56
    /**
57
     *
58
     */
59
    const TYPE_PROJECT_CORE = 'project_core';
60
61
    /**
62
     *
63
     */
64
    const TYPE_PROJECT_MODULE = 'project_module';
65
66
    /**
67
     *
68
     */
69
    const TYPE_PROJECT_THEME = 'project_theme';
70
71
    /**
72
     *
73
     */
74
    const TYPE_UNKNOWN = 'unknown';
75
76
    /**
77
     * @var
78
     */
79
    protected $project;
80
81
    /**
82
     * @var string
83
     */
84
    protected $filename;
85
86
    /**
87
     * @var
88
     */
89
    protected $name;
90
91
    /**
92
     * @var
93
     */
94
    protected $core;
95
96
    /**
97
     * @var
98
     */
99
    protected $version;
100
101
    /**
102
     * @var
103
     */
104
    protected $status_url;
105
106
    /**
107
     * @var
108
     */
109
    protected $install_type;
110
111
    /**
112
     * @var
113
     */
114
    protected $existing_version;
115
116
    /**
117
     * @var
118
     */
119
    protected $existing_major;
120
121
    /**
122
     * @var array
123
     */
124
    protected $data;
125
126
    // Calculated properties.
127
128
    /**
129
     * @var
130
     */
131
    protected $status;
132
133
    /**
134
     * @var
135
     */
136
    protected $project_status;
137
138
    /**
139
     * @var string
140
     */
141
    protected $project_type;
142
143
    /**
144
     * @var
145
     */
146
    protected $reason;
147
148
    /**
149
     * @var
150
     */
151
    protected $fetch_status;
152
153
    /**
154
     * @var
155
     */
156
    protected $latest_version;
157
158
    /**
159
     * @var
160
     */
161
    protected $latest_dev;
162
163
    /**
164
     * @var
165
     */
166
    protected $dev_version;
167
168
    /**
169
     * @var
170
     */
171
    protected $recommended;
172
173
    /**
174
     * @var
175
     */
176
    protected $datestamp;
177
178
    /**
179
     * @var array
180
     */
181
    protected $releases;
182
183
    /**
184
     * @var array
185
     */
186
    protected $security_updates;
187
188
    /**
189
     * @var array
190
     */
191
    protected $also_available;
192
193
    /**
194
     * @param string $project
195
     * @param string $core
196
     * @param string $version
197
     * @param \DateTime|int|null $date
198
     */
199
    public function __construct($project, $core, $version, $date = null)
200
    {
201
        $this->project = $project;
202
        $this->name    = $project;
203
        $this->core    = $core;
204
        $this->version = $version;
205
206
        if ($date instanceof \DateTime) {
207
            $this->datestamp = $date->getTimestamp();
208
        } elseif (is_int($date)) {
209
            $this->datestamp = $date;
210
        }
211
212
        $this->project_type = self::TYPE_UNKNOWN;
213
214
        $this->releases         = array();
215
        $this->security_updates = array();
216
        $this->also_available   = array();
217
218
        $this->init();
219
    }
220
221
    /**
222
     * @return string
223
     */
224
    public function getFilename()
225
    {
226
        return $this->filename;
227
    }
228
229
    /**
230
     * @param string $filename
231
     */
232
    public function setFilename($filename)
233
    {
234
        $this->filename = $filename;
235
236
        $this->init();
237
    }
238
239
    /**
240
     * @return string
241
     */
242
    public function getWorkingDirectory()
243
    {
244
        if ($this->getProject() == 'drupal' && $this->getCore() == '8.x') {
245
            $path = str_replace('\\', '/', dirname($this->getFilename()));
246
247
            // Todo: Optimize.
248 View Code Duplication
            if (($position = strpos($path, '/core/modules/')) !== false) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
249
                return substr($path, 0, $position);
250
            }
251 View Code Duplication
            if (($position = strpos($path, '/core/profiles/')) !== false) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
252
                return substr($path, 0, $position);
253
            }
254 View Code Duplication
            if (($position = strpos($path, '/core/themes/')) !== false) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
255
                return substr($path, 0, $position);
256
            }
257 View Code Duplication
            if (($position = strpos($path, '/core/tests/')) !== false) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
258
                return substr($path, 0, $position);
259
            }
260
        } elseif ($this->getProject() == 'drupal' && $this->getCore() == '7.x') {
261
            return dirname($this->getFilename()) . '/../..';
262
        }
263
264
        return dirname($this->getFilename());
265
    }
266
267
    /**
268
     *
269
     */
270
    protected function init()
271
    {
272
        // Patch project if Drupal detected.
273
        if (isset($this->data['package']) && strtolower($this->data['package']) == 'core') {
274
            $this->name = 'Drupal';
275
276
            $this->data = array(
277
              'name' => $this->name,
278
              'description' => '',
279
              'package' => $this->data['package'],
280
              'core' => $this->data['core'],
281
              'version' => $this->data['version'],
282
              'files' => array(),
283
              'configure' => '',
284
              'project' => 'drupal',
285
              'datestamp' => $this->data['datestamp'],
286
            );
287
        }
288
289
        $this->status_url = self::UPDATE_DEFAULT_URL;
290
291
        // Assume an official release until we see otherwise.
292
        $this->install_type     = self::INSTALL_TYPE_OFFICIAL;
293
        $this->existing_version = $this->version;
294
295
        if (isset($this->version)) {
296
            // Check for development snapshots
297
            if (preg_match('/(dev|HEAD)/', $this->version)) {
298
                $this->install_type = self::INSTALL_TYPE_DEV;
299
            }
300
301
            // Figure out what the currently installed major version is. We need
302
            // to handle both contribution (e.g. "5.x-1.3", major = 1) and core
303
            // (e.g. "5.1", major = 5) version strings.
304
            $matches = array();
305
            if (preg_match('/^(\d+\.x-)?(\d+)\..*$/', $this->version, $matches)) {
306
                $this->existing_major = $matches[2];
307
            } else {
308
                // This would only happen for version strings that don't follow the
309
                // drupal.org convention. We let contribs define "major" in their
310
                // .info in this case, and only if that's missing would we hit this.
311
                $this->existing_major = -1;
312
            }
313
        } else {
314
            // No version info available at all.
315
            $this->install_type     = self::INSTALL_TYPE_UNKNOWN;
316
            $this->existing_version = 'Unknown';
317
            $this->existing_major   = -1;
318
        }
319
    }
320
321
    /**
322
     * @param string  $version
323
     * @param Release $release
324
     */
325
    public function addSecurityUpdate($version, $release)
326
    {
327
        $this->security_updates[$version] = $release;
328
    }
329
330
    /**
331
     * @param string $version_major
332
     * @param string $version
333
     */
334
    public function addAlsoAvailable($version_major, $version)
335
    {
336
        $this->also_available[$version_major] = $version;
337
    }
338
339
    /**
340
     * @return array
341
     */
342
    public function getAlsoAvailable()
343
    {
344
        return $this->also_available;
345
    }
346
347
    /**
348
     * @param string $version_major
349
     * @return bool
350
     */
351
    public function hasAlsoAvailable($version_major)
352
    {
353
        return isset($this->also_available[$version_major]);
354
    }
355
356
    /**
357
     * @return mixed
358
     */
359
    public function getCore()
360
    {
361
        return $this->core;
362
    }
363
364
    /**
365
     * @return mixed
366
     */
367
    public function getDatestamp()
368
    {
369
        return $this->datestamp;
370
    }
371
372
    /**
373
     * @return array
374
     */
375
    public function getDetails()
376
    {
377
        return $this->data;
378
    }
379
380
    /**
381
     * @return string
382
     */
383
    public function getProjectType()
384
    {
385
        return $this->project_type;
386
    }
387
388
    /**
389
     * @param string $type
390
     */
391
    public function setProjectType($type)
392
    {
393
        $this->project_type = $type;
394
    }
395
396
    /**
397
     * @return mixed
398
     */
399
    public function getDevVersion()
400
    {
401
        return $this->dev_version;
402
    }
403
404
    /**
405
     * @param $dev_version
406
     */
407
    public function setDevVersion($dev_version)
408
    {
409
        $this->dev_version = $dev_version;
410
    }
411
412
    /**
413
     * @return string
414
     */
415
    public function getExistingMajor()
416
    {
417
        return $this->existing_major;
418
    }
419
420
    /**
421
     * @return string
422
     */
423
    public function getExistingVersion()
424
    {
425
        return $this->existing_version;
426
    }
427
428
    /**
429
     * @return integer
430
     */
431
    public function getFetchStatus()
432
    {
433
        return $this->fetch_status;
434
    }
435
436
    /**
437
     * @param $fetch_status
438
     */
439
    public function setFetchStatus($fetch_status)
440
    {
441
        $this->fetch_status = $fetch_status;
442
    }
443
444
    /**
445
     * @return string
446
     */
447
    public function getInstallType()
448
    {
449
        return $this->install_type;
450
    }
451
452
    /**
453
     * @return mixed
454
     */
455
    public function getLatestDev()
456
    {
457
        return $this->latest_dev;
458
    }
459
460
    /**
461
     * @param $latest_dev
462
     */
463
    public function setLatestDev($latest_dev)
464
    {
465
        $this->latest_dev = $latest_dev;
466
    }
467
468
    /**
469
     * @return mixed
470
     */
471
    public function getLatestVersion()
472
    {
473
        return $this->latest_version;
474
    }
475
476
    /**
477
     * @param $latest_version
478
     */
479
    public function setLatestVersion($latest_version)
480
    {
481
        $this->latest_version = $latest_version;
482
    }
483
484
    /**
485
     * @return string
486
     */
487
    public function getName()
488
    {
489
        return $this->name;
490
    }
491
492
    /**
493
     * @return string
494
     */
495
    public function getProject()
496
    {
497
        return $this->project;
498
    }
499
500
    /**
501
     * @return int
502
     */
503
    public function getProjectStatus()
504
    {
505
        return $this->project_status;
506
    }
507
508
    /**
509
     * @param int $project_status
510
     */
511
    public function setProjectStatus($project_status)
512
    {
513
        $this->project_status = $project_status;
514
    }
515
516
    /**
517
     * @return string
518
     */
519
    public function getReason()
520
    {
521
        return $this->reason;
522
    }
523
524
    /**
525
     * @param string $reason
526
     */
527
    public function setReason($reason)
528
    {
529
        $this->reason = $reason;
530
    }
531
532
    /**
533
     * @return mixed
534
     */
535
    public function getRecommended()
536
    {
537
        return $this->recommended;
538
    }
539
540
    /**
541
     * @param $recommended
542
     */
543
    public function setRecommended($recommended)
544
    {
545
        $this->recommended = $recommended;
546
    }
547
548
    /**
549
     * @return Release[]
550
     */
551
    public function getReleases()
552
    {
553
        return $this->releases;
554
    }
555
556
    /**
557
     * @param Release[] $releases
558
     */
559
    public function setReleases($releases)
560
    {
561
        $this->releases = $releases;
562
    }
563
564
    /**
565
     * @param string $release
566
     *
567
     * @return Release|false
568
     */
569
    public function getRelease($release)
570
    {
571
        if (isset($this->releases[$release])) {
572
            return $this->releases[$release];
573
        }
574
575
        return false;
576
    }
577
578
    /**
579
     * @return Release[]
580
     */
581
    public function getSecurityUpdates()
582
    {
583
        return $this->security_updates;
584
    }
585
586
    /**
587
     * @param Release[] $security_updates
588
     */
589
    public function setSecurityUpdates($security_updates)
590
    {
591
        $this->security_updates = $security_updates;
592
    }
593
594
    /**
595
     * @return int
596
     */
597
    public function getStatus()
598
    {
599
        return $this->status;
600
    }
601
602
    /**
603
     * @param int $status
604
     */
605
    public function setStatus($status)
606
    {
607
        $this->status = $status;
608
    }
609
610
    /**
611
     * @return string
612
     */
613
    public function getStatusUrl()
614
    {
615
        return $this->status_url;
616
    }
617
618
    /**
619
     * @param string $status_url
620
     */
621
    public function setStatusUrl($status_url)
622
    {
623
        $this->status_url = $status_url;
624
    }
625
626
    /**
627
     * @return string
628
     */
629
    public function getVersion()
630
    {
631
        return $this->version;
632
    }
633
634
    /**
635
     * @return bool
636
     */
637
    public function hasSecurityUpdates()
638
    {
639
        return count($this->security_updates) > 0;
640
    }
641
642
    /**
643
     * @param array $data
644
     */
645
    public function setDetails($data)
646
    {
647
        $this->data = $data;
648
649
        foreach (array('name', 'core', 'version', 'datestamp') as $property) {
650
            if (isset($data[$property])) {
651
                $this->$property = $data[$property];
652
            }
653
        }
654
655
        $this->init();
656
    }
657
658
    /**
659
     * @param string  $version
660
     * @param Release $release
661
     */
662
    public function setRelease($version, Release $release)
663
    {
664
        $this->releases[$version] = $release;
665
    }
666
}
667