Completed
Push — master ( 41d4aa...7dfe14 )
by Damian
02:52
created

SideReport_BrokenLinks::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 3

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 4
rs 10
cc 1
eloc 3
nc 1
nop 0
1
<?php
2
3
/**
4
 * Content side-report listing pages with broken links
5
 * @package cms
6
 * @subpackage content
7
 */
8
9
class BrokenLinksReport extends SS_Report {
10
11
	public function title() {
12
		return _t('BrokenLinksReport.BROKENLINKS',"Broken links report");
13
	}
14
	
15
	public function sourceRecords($params, $sort, $limit) {
16
		$join = '';
17
		$sortBrokenReason = false;
18
		if($sort) {
19
			$parts = explode(' ', $sort);
20
			$field = $parts[0];
21
			$direction = $parts[1];
22
			
23
			if($field == 'AbsoluteLink') {
24
				$sort = 'URLSegment ' . $direction;
25
			} elseif($field == 'Subsite.Title') {
26
				$join = 'LEFT JOIN "Subsite" ON "Subsite"."ID" = "SiteTree"."SubsiteID"';
27
			} elseif($field == 'BrokenReason') {
28
				$sortBrokenReason = true;
29
				$sort = '';
30
			}
31
		}
32
		$brokenFilter = array(
33
			'"SiteTree"."HasBrokenLink" = ? OR "SiteTree"."HasBrokenFile" = ?' => array(true, true)
34
		);
35
		$isLive = !isset($params['CheckSite']) || $params['CheckSite'] == 'Published';
36
		if ($isLive) {
37
			$ret = Versioned::get_by_stage('SiteTree', 'Live', $brokenFilter, $sort, $join, $limit);
0 ignored issues
show
Documentation introduced by
$brokenFilter is of type array<string,array<integ...,\"1\":\"boolean\"}>"}>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
38
		} else {
39
			$ret = DataObject::get('SiteTree', $brokenFilter, $sort, $join, $limit);
40
		}
41
		
42
		$returnSet = new ArrayList();
43
		if ($ret) foreach($ret as $record) {
44
			$reason = false;
45
			$isRedirectorPage = in_array($record->ClassName, ClassInfo::subclassesFor('RedirectorPage'));
46
			$isVirtualPage = in_array($record->ClassName, ClassInfo::subclassesFor('VirtualPage'));
47
			
48
			if ($isVirtualPage) {
49
				if ($record->HasBrokenLink) {
50
					$reason = _t('BrokenLinksReport.VirtualPageNonExistent', "virtual page pointing to non-existent page");
51
					$reasonCodes = array("VPBROKENLINK");
52
				}
53
			} else if ($isRedirectorPage) {
54
				if ($record->HasBrokenLink) {
55
					$reason = _t('BrokenLinksReport.RedirectorNonExistent', "redirector page pointing to non-existent page");
56
					$reasonCodes = array("RPBROKENLINK");
57
				}
58
			} else {
59
				if ($record->HasBrokenLink && $record->HasBrokenFile) {
60
					$reason = _t('BrokenLinksReport.HasBrokenLinkAndFile', "has broken link and file");
61
					$reasonCodes = array("BROKENFILE", "BROKENLINK");
62
				} else if ($record->HasBrokenLink && !$record->HasBrokenFile) {
63
					$reason = _t('BrokenLinksReport.HasBrokenLink', "has broken link");
64
					$reasonCodes = array("BROKENLINK");
65
				} else if (!$record->HasBrokenLink && $record->HasBrokenFile) {
66
					$reason = _t('BrokenLinksReport.HasBrokenFile', "has broken file");
67
					$reasonCodes = array("BROKENFILE");
68
				}
69
			}
70
			
71
			if ($reason) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $reason of type string|false is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
72
				if (isset($params['Reason']) && $params['Reason'] && !in_array($params['Reason'], $reasonCodes)) continue;
0 ignored issues
show
Bug introduced by
The variable $reasonCodes does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
73
				$record->BrokenReason = $reason;
74
				$returnSet->push($record);
75
			}
76
		}
77
		
78
		if($sortBrokenReason) $returnSet = $returnSet->sort('BrokenReason', $direction);
0 ignored issues
show
Bug introduced by
The variable $direction does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
79
		
80
		return $returnSet;
81
	}
82
	public function columns() {
83
		if(isset($_REQUEST['filters']['CheckSite']) && $_REQUEST['filters']['CheckSite'] == 'Draft') {
84
			$dateTitle = _t('BrokenLinksReport.ColumnDateLastModified', 'Date last modified');
85
		} else {
86
			$dateTitle = _t('BrokenLinksReport.ColumnDateLastPublished', 'Date last published');
87
		}
88
		
89
		$linkBase = singleton('CMSPageEditController')->Link('show');
90
		$fields = array(
91
			"Title" => array(
92
				"title" => _t('BrokenLinksReport.PageName', 'Page name'),
93
				'formatting' => function($value, $item) use ($linkBase) {
94
					return sprintf('<a href="%s" title="%s">%s</a>',
95
						Controller::join_links($linkBase, $item->ID),
96
						_t('BrokenLinksReport.HoverTitleEditPage', 'Edit page'),
97
						$value
98
					);
99
				}
100
			),
101
			"LastEdited" => array(
102
				"title" => $dateTitle,
103
				'casting' => 'SS_Datetime->Full'
104
			),
105
			"BrokenReason" => array(
106
				"title" => _t('BrokenLinksReport.ColumnProblemType', "Problem type")
107
			),
108
			'AbsoluteLink' => array(
109
				'title' => _t('BrokenLinksReport.ColumnURL', 'URL'),
110
				'formatting' => function($value, $item) {
111
					$liveLink = $item->AbsoluteLiveLink;
112
					$stageLink = $item->AbsoluteLink();
113
					return sprintf('%s <a href="%s">%s</a>',
114
						$stageLink,
115
						$liveLink ? $liveLink : $stageLink . '?stage=Stage',
116
						$liveLink ? '(live)' : '(draft)'
117
					);
118
				}
119
			)
120
		);
121
		
122
		return $fields;
123
	}
124
	public function parameterFields() {
125
		return new FieldList(
126
			new DropdownField('CheckSite', _t('BrokenLinksReport.CheckSite','Check site'), array(
127
				'Published' => _t('BrokenLinksReport.CheckSiteDropdownPublished', 'Published Site'),
128
				'Draft' => _t('BrokenLinksReport.CheckSiteDropdownDraft', 'Draft Site')
129
			)),
130
			new DropdownField(
131
				'Reason',
132
				_t('BrokenLinksReport.ReasonDropdown', 'Problem to check'),
133
				array(
134
					'' => _t('BrokenLinksReport.Any', 'Any'),
135
					'BROKENFILE' => _t('BrokenLinksReport.ReasonDropdownBROKENFILE', 'Broken file'),
136
					'BROKENLINK' => _t('BrokenLinksReport.ReasonDropdownBROKENLINK', 'Broken link'),
137
					'VPBROKENLINK' => _t('BrokenLinksReport.ReasonDropdownVPBROKENLINK', 'Virtual page pointing to non-existent page'),
138
					'RPBROKENLINK' => _t('BrokenLinksReport.ReasonDropdownRPBROKENLINK', 'Redirector page pointing to non-existent page'),
139
				)
140
			)
141
		);
142
	}
143
}
144
145
146
/**
147
 * @deprecated 3.2..4.0
148
 */
149
class SideReport_BrokenLinks extends BrokenLinksReport {
150
	public function __construct() {
151
		Deprecation::notice('4.0', 'Use BrokenLinksReport instead');
152
		parent::__construct();
153
	}
154
}
155