Passed
Push — master ( 8f5e6a...061d3e )
by Felipe
03:26
created

GanttScale   D

Complexity

Total Complexity 179

Size/Duplication

Total Lines 1145
Duplicated Lines 5.5 %

Coupling/Cohesion

Components 1
Dependencies 4

Importance

Changes 0
Metric Value
dl 63
loc 1145
rs 4
c 0
b 0
f 0
wmc 179
lcom 1
cbo 4

46 Methods

Rating   Name   Duplication   Size   Complexity  
B __construct() 0 43 1
A ShowHeaders() 0 18 3
A UseWeekendBackground() 0 4 1
A IsRangeSet() 0 4 2
A SetVertLayout() 0 4 1
A SetDateLocale() 0 4 1
A GetNumberOfDays() 0 4 1
A GetPlotWidth() 0 5 1
A SetLabelWidth() 0 4 1
A SetWeekStart() 0 7 1
A IsDisplayMinute() 0 4 1
A IsDisplayHour() 0 4 1
A IsDisplayDay() 0 4 1
A IsDisplayWeek() 0 4 1
A IsDisplayMonth() 0 4 1
A IsDisplayYear() 0 4 1
A SetVertSpacing() 0 4 1
A SetRange() 0 5 1
B AdjustStartEndDay() 0 34 6
A SetTableTitleBackground() 0 4 1
C GetHeaderHeight() 0 30 7
A GetDayWidth() 0 4 1
A GetHourWidth() 0 4 1
A GetMinuteWidth() 0 4 1
A GetNumDaysInYear() 0 8 2
B GetWeekNbr() 0 37 2
A IsLeap() 0 12 4
A GetYear() 0 4 1
A GetNumDaysInMonth() 0 10 2
A GetMonthDayNbr() 0 4 1
A GetYearDayNbr() 0 4 1
A GetMonthNbr() 0 4 1
B TranslateDate() 0 26 3
B TranslateVertPos() 0 22 4
A GetVertSpacing() 0 4 1
B NormalizeDate() 0 21 7
A TimeToMinutes() 0 15 2
D StrokeMinutes() 20 94 18
D StrokeHours() 10 86 16
F StrokeDays() 10 121 24
C StrokeWeeks() 0 74 16
C GetMonthLabel() 0 29 8
C StrokeMonths() 11 67 10
B StrokeYears() 12 61 8
B StrokeTableHeaders() 0 48 5
B Stroke() 0 46 5

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

1
<?php
2
namespace Amenadiel\JpGraph\Graph;
3
4
use Amenadiel\JpGraph\Util;
5
6
//===================================================
7
// CLASS GanttScale
8
// Description: Responsible for calculating and showing
9
// the scale in a gantt chart. This includes providing methods for
10
// converting dates to position in the chart as well as stroking the
11
// date headers (days, week, etc).
12
//===================================================
13
class GanttScale
14
{
15
    public $minute;
16
    public $hour;
17
    public $day;
18
    public $week;
19
    public $month;
20
    public $year;
21
    public $divider;
22
    public $dividerh;
23
    public $tableTitle;
24
    public $iStartDate = -1;
25
    public $iEndDate = -1;
26
    // Number of gantt bar position (n.b not necessariliy the same as the number of bars)
27
    // we could have on bar in position 1, and one bar in position 5 then there are two
28
    // bars but the number of bar positions is 5
29
    public $actinfo;
30
    public $iTopPlotMargin  = 10;
31
    public $iBottomPlotMargin  = 15;
32
    public $iVertLines      = -1;
33
    public $iVertHeaderSize = -1;
34
    // The width of the labels (defaults to the widest of all labels)
35
    private $iLabelWidth;
36
    // Out image to stroke the scale to
37
    private $iImg;
38
    private $iTableHeaderBackgroundColor = "white";
39
    private $iTableHeaderFrameColor = "black";
40
    private $iTableHeaderFrameWeight     = 1;
41
    private $iAvailableHeight            = -1;
42
    private $iVertSpacing            = -1;
43
    private $iDateLocale;
44
    private $iVertLayout               = GANTT_EVEN;
45
    private $iUsePlotWeekendBackground = true;
46
    private $iWeekStart                = 1; // Default to have weekends start on Monday
47
48
    //---------------
49
    // CONSTRUCTOR
50
    public function __construct($aImg)
51
    {
52
        $this->iImg        = $aImg;
53
        $this->iDateLocale = new DateLocale();
54
55
        $this->minute = new HeaderProperty();
56
        $this->minute->SetIntervall(15);
57
        $this->minute->SetLabelFormatString('i');
58
        $this->minute->SetFont(FF_FONT0);
59
        $this->minute->grid->SetColor("gray");
60
61
        $this->hour = new HeaderProperty();
62
        $this->hour->SetFont(FF_FONT0);
63
        $this->hour->SetIntervall(6);
64
        $this->hour->SetStyle(HOURSTYLE_HM24);
65
        $this->hour->SetLabelFormatString('H:i');
66
        $this->hour->grid->SetColor("gray");
67
68
        $this->day = new HeaderProperty();
69
        $this->day->grid->SetColor("gray");
70
        $this->day->SetLabelFormatString('l');
71
72
        $this->week = new HeaderProperty();
73
        $this->week->SetLabelFormatString("w%d");
74
        $this->week->SetFont(FF_FONT1);
75
76
        $this->month = new HeaderProperty();
77
        $this->month->SetFont(FF_FONT1, FS_BOLD);
78
79
        $this->year = new HeaderProperty();
80
        $this->year->SetFont(FF_FONT1, FS_BOLD);
81
82
        $this->divider  = new LineProperty();
83
        $this->dividerh = new LineProperty();
84
        $this->dividerh->SetWeight(2);
85
        $this->divider->SetWeight(6);
86
        $this->divider->SetColor('gray');
87
        $this->divider->SetStyle('fancy');
88
89
        $this->tableTitle = new TextProperty();
90
        $this->tableTitle->Show(false);
91
        $this->actinfo = new GanttActivityInfo();
92
    }
93
94
    //---------------
95
    // PUBLIC METHODS
96
    // Specify what headers should be visible
97
    public function ShowHeaders($aFlg)
98
    {
99
        $this->day->Show($aFlg & GANTT_HDAY);
100
        $this->week->Show($aFlg & GANTT_HWEEK);
101
        $this->month->Show($aFlg & GANTT_HMONTH);
102
        $this->year->Show($aFlg & GANTT_HYEAR);
103
        $this->hour->Show($aFlg & GANTT_HHOUR);
104
        $this->minute->Show($aFlg & GANTT_HMIN);
105
106
        // Make some default settings of gridlines whihc makes sense
107
        if ($aFlg & GANTT_HWEEK) {
108
            $this->month->grid->Show(false);
109
            $this->year->grid->Show(false);
110
        }
111
        if ($aFlg & GANTT_HHOUR) {
112
            $this->day->grid->SetColor("black");
113
        }
114
    }
115
116
    // Should the weekend background stretch all the way down in the plotarea
117
    public function UseWeekendBackground($aShow)
118
    {
119
        $this->iUsePlotWeekendBackground = $aShow;
120
    }
121
122
    // Have a range been specified?
123
    public function IsRangeSet()
124
    {
125
        return $this->iStartDate != -1 && $this->iEndDate != -1;
126
    }
127
128
    // Should the layout be from top or even?
129
    public function SetVertLayout($aLayout)
130
    {
131
        $this->iVertLayout = $aLayout;
132
    }
133
134
    // Which locale should be used?
135
    public function SetDateLocale($aLocale)
136
    {
137
        $this->iDateLocale->Set($aLocale);
138
    }
139
140
    // Number of days we are showing
141
    public function GetNumberOfDays()
142
    {
143
        return round(($this->iEndDate - $this->iStartDate) / SECPERDAY);
144
    }
145
146
    // The width of the actual plot area
147
    public function GetPlotWidth()
148
    {
149
        $img = $this->iImg;
150
        return $img->width - $img->left_margin - $img->right_margin;
151
    }
152
153
    // Specify the width of the titles(labels) for the activities
154
    // (This is by default set to the minimum width enought for the
155
    // widest title)
156
    public function SetLabelWidth($aLabelWidth)
157
    {
158
        $this->iLabelWidth = $aLabelWidth;
159
    }
160
161
    // Which day should the week start?
162
    // 0==Sun, 1==Monday, 2==Tuesday etc
163
    public function SetWeekStart($aStartDay)
164
    {
165
        $this->iWeekStart = $aStartDay % 7;
166
167
        //Recalculate the startday since this will change the week start
168
        $this->SetRange($this->iStartDate, $this->iEndDate);
169
    }
170
171
    // Do we show min scale?
172
    public function IsDisplayMinute()
173
    {
174
        return $this->minute->iShowLabels;
175
    }
176
177
    // Do we show day scale?
178
    public function IsDisplayHour()
179
    {
180
        return $this->hour->iShowLabels;
181
    }
182
183
    // Do we show day scale?
184
    public function IsDisplayDay()
185
    {
186
        return $this->day->iShowLabels;
187
    }
188
189
    // Do we show week scale?
190
    public function IsDisplayWeek()
191
    {
192
        return $this->week->iShowLabels;
193
    }
194
195
    // Do we show month scale?
196
    public function IsDisplayMonth()
197
    {
198
        return $this->month->iShowLabels;
199
    }
200
201
    // Do we show year scale?
202
    public function IsDisplayYear()
203
    {
204
        return $this->year->iShowLabels;
205
    }
206
207
    // Specify spacing (in percent of bar height) between activity bars
208
    public function SetVertSpacing($aSpacing)
209
    {
210
        $this->iVertSpacing = $aSpacing;
211
    }
212
213
    // Specify scale min and max date either as timestamp or as date strings
214
    // Always round to the nearest week boundary
215
    public function SetRange($aMin, $aMax)
216
    {
217
        $this->iStartDate = $this->NormalizeDate($aMin);
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->NormalizeDate($aMin) can also be of type false or double. However, the property $iStartDate is declared as type integer. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
218
        $this->iEndDate   = $this->NormalizeDate($aMax);
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->NormalizeDate($aMax) can also be of type false or double. However, the property $iEndDate is declared as type integer. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
219
    }
220
221
    // Adjust the start and end date so they fit to beginning/ending
222
    // of the week taking the specified week start day into account.
223
    public function AdjustStartEndDay()
224
    {
225
        if (!($this->IsDisplayYear() || $this->IsDisplayMonth() || $this->IsDisplayWeek())) {
226
            // Don't adjust
227
            return;
228
        }
229
230
        // Get day in week for start and ending date (Sun==0)
231
        $ds = strftime("%w", $this->iStartDate);
232
        $de = strftime("%w", $this->iEndDate);
233
234
        // We want to start on iWeekStart day. But first we subtract a week
235
        // if the startdate is "behind" the day the week start at.
236
        // This way we ensure that the given start date is always included
237
        // in the range. If we don't do this the nearest correct weekday in the week
238
        // to start at might be later than the start date.
239
        if ($ds < $this->iWeekStart) {
240
            $d = strtotime('-7 day', $this->iStartDate);
241
        } else {
242
            $d = $this->iStartDate;
243
        }
244
245
        $adjdate          = strtotime(($this->iWeekStart - $ds) . ' day', $d/*$this->iStartDate*/);
246
        $this->iStartDate = $adjdate;
247
248
        // We want to end on the last day of the week
249
        $preferredEndDay = ($this->iWeekStart + 6) % 7;
250
        if ($preferredEndDay != $de) {
251
            // Solve equivalence eq:    $de + x ~ $preferredDay (mod 7)
252
            $adj            = (7 + ($preferredEndDay - $de)) % 7;
253
            $adjdate        = strtotime("+$adj day", $this->iEndDate);
254
            $this->iEndDate = $adjdate;
255
        }
256
    }
257
258
    // Specify background for the table title area (upper left corner of the table)
259
    public function SetTableTitleBackground($aColor)
260
    {
261
        $this->iTableHeaderBackgroundColor = $aColor;
262
    }
263
264
    ///////////////////////////////////////
265
    // PRIVATE Methods
266
267
    // Determine the height of all the scale headers combined
268
    public function GetHeaderHeight()
269
    {
270
        $img    = $this->iImg;
271
        $height = 1;
272
        if ($this->minute->iShowLabels) {
273
            $height += $this->minute->GetFontHeight($img);
274
            $height += $this->minute->iTitleVertMargin;
275
        }
276
        if ($this->hour->iShowLabels) {
277
            $height += $this->hour->GetFontHeight($img);
278
            $height += $this->hour->iTitleVertMargin;
279
        }
280
        if ($this->day->iShowLabels) {
281
            $height += $this->day->GetFontHeight($img);
282
            $height += $this->day->iTitleVertMargin;
283
        }
284
        if ($this->week->iShowLabels) {
285
            $height += $this->week->GetFontHeight($img);
286
            $height += $this->week->iTitleVertMargin;
287
        }
288
        if ($this->month->iShowLabels) {
289
            $height += $this->month->GetFontHeight($img);
290
            $height += $this->month->iTitleVertMargin;
291
        }
292
        if ($this->year->iShowLabels) {
293
            $height += $this->year->GetFontHeight($img);
294
            $height += $this->year->iTitleVertMargin;
295
        }
296
        return $height;
297
    }
298
299
    // Get width (in pixels) for a single day
300
    public function GetDayWidth()
301
    {
302
        return ($this->GetPlotWidth() - $this->iLabelWidth + 1) / $this->GetNumberOfDays();
303
    }
304
305
    // Get width (in pixels) for a single hour
306
    public function GetHourWidth()
307
    {
308
        return $this->GetDayWidth() / 24;
309
    }
310
311
    public function GetMinuteWidth()
312
    {
313
        return $this->GetHourWidth() / 60;
314
    }
315
316
    // Nuber of days in a year
317
    public function GetNumDaysInYear($aYear)
318
    {
319
        if ($this->IsLeap($aYear)) {
320
            return 366;
321
        } else {
322
            return 365;
323
        }
324
    }
325
326
    // Get week number
327
    public function GetWeekNbr($aDate, $aSunStart = true)
328
    {
329
        // We can't use the internal strftime() since it gets the weeknumber
330
        // wrong since it doesn't follow ISO on all systems since this is
331
        // system linrary dependent.
332
        // Even worse is that this works differently if we are on a Windows
333
        // or UNIX box (it even differs between UNIX boxes how strftime()
334
        // is natively implemented)
335
        //
336
        // Credit to Nicolas Hoizey <[email protected]> for this elegant
337
        // version of Week Nbr calculation.
338
339
        $day = $this->NormalizeDate($aDate);
340
        if ($aSunStart) {
341
            $day += 60 * 60 * 24;
342
        }
343
344
        /*-------------------------------------------------------------------------
345
        According to ISO-8601 :
346
        "Week 01 of a year is per definition the first week that has the Thursday in this year,
347
        which is equivalent to the week that contains the fourth day of January.
348
        In other words, the first week of a new year is the week that has the majority of its
349
        days in the new year."
350
351
        Be carefull, with PHP, -3 % 7 = -3, instead of 4 !!!
352
353
        day of year             = date("z", $day) + 1
354
        offset to thursday      = 3 - (date("w", $day) + 6) % 7
355
        first thursday of year  = 1 + (11 - date("w", mktime(0, 0, 0, 1, 1, date("Y", $day)))) % 7
356
        week number             = (thursday's day of year - first thursday's day of year) / 7 + 1
357
        ---------------------------------------------------------------------------*/
358
359
        $thursday = $day + 60 * 60 * 24 * (3 - (date("w", $day) + 6) % 7); // take week's thursday
360
        $week     = 1 + (date("z", $thursday) - (11 - date("w", mktime(0, 0, 0, 1, 1, date("Y", $thursday)))) % 7) / 7;
361
362
        return $week;
363
    }
364
365
    // Is year a leap year?
366
    public function IsLeap($aYear)
367
    {
368
        // Is the year a leap year?
369
        //$year = 0+date("Y",$aDate);
1 ignored issue
show
Unused Code Comprehensibility introduced by
62% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
370
        if ($aYear % 4 == 0) {
371
            if (!($aYear % 100 == 0) || ($aYear % 400 == 0)) {
372
                return true;
373
            }
374
        }
375
376
        return false;
377
    }
378
379
    // Get current year
380
    public function GetYear($aDate)
381
    {
382
        return 0 + Date("Y", $aDate);
383
    }
384
385
    // Return number of days in a year
386
    public function GetNumDaysInMonth($aMonth, $aYear)
387
    {
388
        $days  = array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
389
        $daysl = array(31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
390
        if ($this->IsLeap($aYear)) {
391
            return $daysl[$aMonth];
392
        } else {
393
            return $days[$aMonth];
394
        }
395
    }
396
397
    // Get day in month
398
    public function GetMonthDayNbr($aDate)
399
    {
400
        return 0 + strftime("%d", $aDate);
401
    }
402
403
    // Get day in year
404
    public function GetYearDayNbr($aDate)
405
    {
406
        return 0 + strftime("%j", $aDate);
407
    }
408
409
    // Get month number
410
    public function GetMonthNbr($aDate)
411
    {
412
        return 0 + strftime("%m", $aDate);
413
    }
414
415
    // Translate a date to screen coordinates (horizontal scale)
416
    public function TranslateDate($aDate)
417
    {
418
        //
419
        // In order to handle the problem with Daylight savings time
420
        // the scale written with equal number of seconds per day beginning
421
        // with the start date. This means that we "cement" the state of
422
        // DST as it is in the start date. If later the scale includes the
423
        // switchover date (depends on the locale) we need to adjust back
424
        // if the date we try to translate has a different DST status since
425
        // we would otherwise be off by one hour.
426
        $aDate  = $this->NormalizeDate($aDate);
427
        $tmp    = localtime($aDate);
428
        $cloc   = $tmp[8];
429
        $tmp    = localtime($this->iStartDate);
430
        $sloc   = $tmp[8];
431
        $offset = 0;
432
        if ($sloc != $cloc) {
433
            if ($sloc) {
434
                $offset = 3600;
435
            } else {
436
                $offset = -3600;
437
            }
438
        }
439
        $img = $this->iImg;
440
        return ($aDate - $this->iStartDate - $offset) / SECPERDAY * $this->GetDayWidth() + $img->left_margin + $this->iLabelWidth;
441
    }
442
443
    // Get screen coordinatesz for the vertical position for a bar
444
    public function TranslateVertPos($aPos, $atTop = false)
445
    {
446
        $img = $this->iImg;
447
        if ($aPos > $this->iVertLines) {
448
            Util\JpGraphError::RaiseL(6015, $aPos);
449
        }
450
451
        // 'Illegal vertical position %d'
452
        if ($this->iVertLayout == GANTT_EVEN) {
453
            // Position the top bar at 1 vert spacing from the scale
454
            $pos = round($img->top_margin + $this->iVertHeaderSize + ($aPos + 1) * $this->iVertSpacing);
455
        } else {
456
            // position the top bar at 1/2 a vert spacing from the scale
457
            $pos = round($img->top_margin + $this->iVertHeaderSize + $this->iTopPlotMargin + ($aPos + 1) * $this->iVertSpacing);
458
        }
459
460
        if ($atTop) {
461
            $pos -= $this->iVertSpacing;
462
        }
463
464
        return $pos;
465
    }
466
467
    // What is the vertical spacing?
468
    public function GetVertSpacing()
469
    {
470
        return $this->iVertSpacing;
471
    }
472
473
    // Convert a date to timestamp
474
    public function NormalizeDate($aDate)
475
    {
476
        if ($aDate === false) {
477
            return false;
478
        }
479
480
        if (is_string($aDate)) {
481
            $t = strtotime($aDate);
482
            if ($t === false || $t === -1) {
483
                Util\JpGraphError::RaiseL(6016, $aDate);
484
                //("Date string ($aDate) specified for Gantt activity can not be interpretated. Please make sure it is a valid time string, e.g. 2005-04-23 13:30");
485
            }
486
            return $t;
487
        } elseif (is_int($aDate) || is_float($aDate)) {
488
            return $aDate;
489
        } else {
490
            Util\JpGraphError::RaiseL(6017, $aDate);
491
        }
492
493
        //Unknown date format in GanttScale ($aDate).");
494
    }
495
496
    // Convert a time string to minutes
497
498
    public function TimeToMinutes($aTimeString)
499
    {
500
        // Split in hours and minutes
501
        $pos    = strpos($aTimeString, ':');
502
        $minint = 60;
0 ignored issues
show
Unused Code introduced by
$minint is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
503
        if ($pos === false) {
504
            $hourint = $aTimeString;
505
            $minint  = 0;
506
        } else {
507
            $hourint = floor(substr($aTimeString, 0, $pos));
508
            $minint  = floor(substr($aTimeString, $pos + 1));
509
        }
510
        $minint += 60 * $hourint;
511
        return $minint;
512
    }
513
514
    // Stroke the day scale (including gridlines)
515
    public function StrokeMinutes($aYCoord, $getHeight = false)
516
    {
517
        $img = $this->iImg;
518
        $xt  = $img->left_margin + $this->iLabelWidth;
519
        $yt  = $aYCoord + $img->top_margin;
520
        if ($this->minute->iShowLabels) {
521
            $img->SetFont($this->minute->iFFamily, $this->minute->iFStyle, $this->minute->iFSize);
522
            $yb = $yt + $img->GetFontHeight() +
523
            $this->minute->iTitleVertMargin + $this->minute->iFrameWeight;
524
            if ($getHeight) {
525
                return $yb - $img->top_margin;
526
            }
527
            $xb = $img->width - $img->right_margin + 1;
528
            $img->SetColor($this->minute->iBackgroundColor);
529
            $img->FilledRectangle($xt, $yt, $xb, $yb);
530
531
            $x = $xt;
532
            $img->SetTextAlign("center");
533
            $day    = date('w', $this->iStartDate);
534
            $minint = $this->minute->GetIntervall();
535
536
            if (60 % $minint !== 0) {
537
                Util\JpGraphError::RaiseL(6018, $minint);
538
                //'Intervall for minutes must divide the hour evenly, e.g. 1,5,10,12,15,20,30 etc You have specified an intervall of '.$minint.' minutes.');
1 ignored issue
show
Unused Code Comprehensibility introduced by
72% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
539
            }
540
541
            $n         = 60 / $minint;
542
            $datestamp = $this->iStartDate;
543
            $width     = $this->GetHourWidth() / $n;
544
            if ($width < 8) {
545
                // TO small width to draw minute scale
546
                Util\JpGraphError::RaiseL(6019, $width);
547
                //('The available width ('.$width.') for minutes are to small for this scale to be displayed. Please use auto-sizing or increase the width of the graph.');
1 ignored issue
show
Unused Code Comprehensibility introduced by
75% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
548
            }
549
550
            $nh = ceil(24 * 60 / $this->TimeToMinutes($this->hour->GetIntervall()));
551
            $nd = $this->GetNumberOfDays();
552
            // Convert to intervall to seconds
553
            $minint *= 60;
554
            for ($j = 0; $j < $nd; ++$j, $day += 1, $day %= 7) {
555
                for ($k = 0; $k < $nh; ++$k) {
556
                    for ($i = 0; $i < $n; ++$i, $x += $width, $datestamp += $minint) {
557 View Code Duplication
                        if ($day == 6 || $day == 0) {
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...
558
                            $img->PushColor($this->day->iWeekendBackgroundColor);
559
                            if ($this->iUsePlotWeekendBackground) {
560
                                $img->FilledRectangle($x, $yt + $this->day->iFrameWeight, $x + $width, $img->height - $img->bottom_margin);
561
                            } else {
562
                                $img->FilledRectangle($x, $yt + $this->day->iFrameWeight, $x + $width, $yb - $this->day->iFrameWeight);
563
                            }
564
565
                            $img->PopColor();
566
                        }
567
568
                        if ($day == 0) {
569
                            $img->SetColor($this->day->iSundayTextColor);
570
                        } else {
571
                            $img->SetColor($this->day->iTextColor);
572
                        }
573
574 View Code Duplication
                        switch ($this->minute->iStyle) {
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...
575
                            case MINUTESTYLE_CUSTOM:
576
                                $txt = date($this->minute->iLabelFormStr, $datestamp);
577
                                break;
578
                            case MINUTESTYLE_MM:
579
                            default:
580
                                // 15
581
                                $txt = date('i', $datestamp);
582
                                break;
583
                        }
584
                        $img->StrokeText(round($x + $width / 2), round($yb - $this->minute->iTitleVertMargin), $txt);
585
586
                        // Fix a rounding problem the wrong way ..
587
                        // If we also have hour scale then don't draw the firsta or last
588
                        // gridline since that will be overwritten by the hour scale gridline if such exists.
589
                        // However, due to the propagation of rounding of the 'x+=width' term in the loop
590
                        // this might sometimes be one pixel of so we fix this by not drawing it.
591
                        // The proper way to fix it would be to re-calculate the scale for each step and
592
                        // not using the additive term.
593
                        if (!(($i == $n || $i == 0) && $this->hour->iShowLabels && $this->hour->grid->iShow)) {
594
                            $img->SetColor($this->minute->grid->iColor);
595
                            $img->SetLineWeight($this->minute->grid->iWeight);
596
                            $img->Line($x, $yt, $x, $yb);
597
                            $this->minute->grid->Stroke($img, $x, $yb, $x, $img->height - $img->bottom_margin);
598
                        }
599
                    }
600
                }
601
            }
602
            $img->SetColor($this->minute->iFrameColor);
603
            $img->SetLineWeight($this->minute->iFrameWeight);
604
            $img->Rectangle($xt, $yt, $xb, $yb);
605
            return $yb - $img->top_margin;
606
        }
607
        return $aYCoord;
608
    }
609
610
    // Stroke the day scale (including gridlines)
611
    public function StrokeHours($aYCoord, $getHeight = false)
612
    {
613
        $img = $this->iImg;
614
        $xt  = $img->left_margin + $this->iLabelWidth;
615
        $yt  = $aYCoord + $img->top_margin;
616
        if ($this->hour->iShowLabels) {
617
            $img->SetFont($this->hour->iFFamily, $this->hour->iFStyle, $this->hour->iFSize);
618
            $yb = $yt + $img->GetFontHeight() +
619
            $this->hour->iTitleVertMargin + $this->hour->iFrameWeight;
620
            if ($getHeight) {
621
                return $yb - $img->top_margin;
622
            }
623
            $xb = $img->width - $img->right_margin + 1;
624
            $img->SetColor($this->hour->iBackgroundColor);
625
            $img->FilledRectangle($xt, $yt, $xb, $yb);
626
627
            $x = $xt;
628
            $img->SetTextAlign("center");
629
            $tmp    = $this->hour->GetIntervall();
630
            $minint = $this->TimeToMinutes($tmp);
631
            if (1440 % $minint !== 0) {
632
                Util\JpGraphError::RaiseL(6020, $tmp);
633
                //('Intervall for hours must divide the day evenly, e.g. 0:30, 1:00, 1:30, 4:00 etc. You have specified an intervall of '.$tmp);
1 ignored issue
show
Unused Code Comprehensibility introduced by
84% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
634
            }
635
636
            $n         = ceil(24 * 60 / $minint);
637
            $datestamp = $this->iStartDate;
638
            $day       = date('w', $this->iStartDate);
639
            $doback    = !$this->minute->iShowLabels;
640
            $width     = $this->GetDayWidth() / $n;
641
            for ($j = 0; $j < $this->GetNumberOfDays(); ++$j, $day += 1, $day %= 7) {
642
                for ($i = 0; $i < $n; ++$i, $x += $width) {
643 View Code Duplication
                    if ($day == 6 || $day == 0) {
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...
644
                        $img->PushColor($this->day->iWeekendBackgroundColor);
645
                        if ($this->iUsePlotWeekendBackground && $doback) {
646
                            $img->FilledRectangle($x, $yt + $this->day->iFrameWeight, $x + $width, $img->height - $img->bottom_margin);
647
                        } else {
648
                            $img->FilledRectangle($x, $yt + $this->day->iFrameWeight, $x + $width, $yb - $this->day->iFrameWeight);
649
                        }
650
651
                        $img->PopColor();
652
                    }
653
654
                    if ($day == 0) {
655
                        $img->SetColor($this->day->iSundayTextColor);
656
                    } else {
657
                        $img->SetColor($this->day->iTextColor);
658
                    }
659
660
                    switch ($this->hour->iStyle) {
661
                        case HOURSTYLE_HMAMPM:
662
                            // 1:35pm
663
                            $txt = date('g:ia', $datestamp);
664
                            break;
665
                        case HOURSTYLE_H24:
666
                            // 13
667
                            $txt = date('H', $datestamp);
668
                            break;
669
                        case HOURSTYLE_HAMPM:
670
                            $txt = date('ga', $datestamp);
671
                            break;
672
                        case HOURSTYLE_CUSTOM:
673
                            $txt = date($this->hour->iLabelFormStr, $datestamp);
674
                            break;
675
                        case HOURSTYLE_HM24:
676
                        default:
677
                            $txt = date('H:i', $datestamp);
678
                            break;
679
                    }
680
                    $img->StrokeText(round($x + $width / 2), round($yb - $this->hour->iTitleVertMargin), $txt);
681
                    $img->SetColor($this->hour->grid->iColor);
682
                    $img->SetLineWeight($this->hour->grid->iWeight);
683
                    $img->Line($x, $yt, $x, $yb);
684
                    $this->hour->grid->Stroke($img, $x, $yb, $x, $img->height - $img->bottom_margin);
685
                    //$datestamp += $minint*60
1 ignored issue
show
Unused Code Comprehensibility introduced by
38% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
686
                    $datestamp = mktime(date('H', $datestamp), date('i', $datestamp) + $minint, 0,
687
                        date("m", $datestamp), date("d", $datestamp) + 1, date("Y", $datestamp));
688
                }
689
            }
690
            $img->SetColor($this->hour->iFrameColor);
691
            $img->SetLineWeight($this->hour->iFrameWeight);
692
            $img->Rectangle($xt, $yt, $xb, $yb);
693
            return $yb - $img->top_margin;
694
        }
695
        return $aYCoord;
696
    }
697
698
    // Stroke the day scale (including gridlines)
699
    public function StrokeDays($aYCoord, $getHeight = false)
700
    {
701
        $img      = $this->iImg;
702
        $daywidth = $this->GetDayWidth();
703
        $xt       = $img->left_margin + $this->iLabelWidth;
704
        $yt       = $aYCoord + $img->top_margin;
705
        if ($this->day->iShowLabels) {
706
            $img->SetFont($this->day->iFFamily, $this->day->iFStyle, $this->day->iFSize);
707
            $yb = $yt + $img->GetFontHeight() + $this->day->iTitleVertMargin + $this->day->iFrameWeight;
708
            if ($getHeight) {
709
                return $yb - $img->top_margin;
710
            }
711
            $xb = $img->width - $img->right_margin + 1;
712
            $img->SetColor($this->day->iBackgroundColor);
713
            $img->FilledRectangle($xt, $yt, $xb, $yb);
714
715
            $x = $xt;
716
            $img->SetTextAlign("center");
717
            $day       = date('w', $this->iStartDate);
718
            $datestamp = $this->iStartDate;
719
720
            $doback = !($this->hour->iShowLabels || $this->minute->iShowLabels);
721
722
            setlocale(LC_TIME, $this->iDateLocale->iLocale);
723
724
            for ($i = 0; $i < $this->GetNumberOfDays(); ++$i, $x += $daywidth, $day += 1, $day %= 7) {
725 View Code Duplication
                if ($day == 6 || $day == 0) {
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...
726
                    $img->SetColor($this->day->iWeekendBackgroundColor);
727
                    if ($this->iUsePlotWeekendBackground && $doback) {
728
                        $img->FilledRectangle($x, $yt + $this->day->iFrameWeight,
729
                            $x + $daywidth, $img->height - $img->bottom_margin);
730
                    } else {
731
                        $img->FilledRectangle($x, $yt + $this->day->iFrameWeight,
732
                            $x + $daywidth, $yb - $this->day->iFrameWeight);
733
                    }
734
                }
735
736
                $mn = strftime('%m', $datestamp);
737
                if ($mn[0] == '0') {
738
                    $mn = $mn[1];
739
                }
740
741
                switch ($this->day->iStyle) {
742
                    case DAYSTYLE_LONG:
743
                        // "Monday"
744
                        $txt = strftime('%A', $datestamp);
745
                        break;
746
                    case DAYSTYLE_SHORT:
747
                        // "Mon"
748
                        $txt = strftime('%a', $datestamp);
749
                        break;
750
                    case DAYSTYLE_SHORTDAYDATE1:
751
                        // "Mon 23/6"
752
                        $txt = strftime('%a %d/' . $mn, $datestamp);
753
                        break;
754
                    case DAYSTYLE_SHORTDAYDATE2:
755
                        // "Mon 23 Jun"
756
                        $txt = strftime('%a %d %b', $datestamp);
757
                        break;
758
                    case DAYSTYLE_SHORTDAYDATE3:
759
                        // "Mon 23 Jun 2003"
760
                        $txt = strftime('%a %d %b %Y', $datestamp);
761
                        break;
762
                    case DAYSTYLE_LONGDAYDATE1:
763
                        // "Monday 23 Jun"
764
                        $txt = strftime('%A %d %b', $datestamp);
765
                        break;
766
                    case DAYSTYLE_LONGDAYDATE2:
767
                        // "Monday 23 Jun 2003"
768
                        $txt = strftime('%A %d %b %Y', $datestamp);
769
                        break;
770
                    case DAYSTYLE_SHORTDATE1:
771
                        // "23/6"
772
                        $txt = strftime('%d/' . $mn, $datestamp);
773
                        break;
774
                    case DAYSTYLE_SHORTDATE2:
775
                        // "23 Jun"
776
                        $txt = strftime('%d %b', $datestamp);
777
                        break;
778
                    case DAYSTYLE_SHORTDATE3:
779
                        // "Mon 23"
780
                        $txt = strftime('%a %d', $datestamp);
781
                        break;
782
                    case DAYSTYLE_SHORTDATE4:
783
                        // "23"
784
                        $txt = strftime('%d', $datestamp);
785
                        break;
786
                    case DAYSTYLE_CUSTOM:
787
                        // Custom format
788
                        $txt = strftime($this->day->iLabelFormStr, $datestamp);
789
                        break;
790
                    case DAYSTYLE_ONELETTER:
791
                    default:
792
                        // "M"
793
                        $txt = strftime('%A', $datestamp);
794
                        $txt = strtoupper($txt[0]);
795
                        break;
796
                }
797
798
                if ($day == 0) {
799
                    $img->SetColor($this->day->iSundayTextColor);
800
                } else {
801
                    $img->SetColor($this->day->iTextColor);
802
                }
803
804
                $img->StrokeText(round($x + $daywidth / 2 + 1),
805
                    round($yb - $this->day->iTitleVertMargin), $txt);
806
                $img->SetColor($this->day->grid->iColor);
807
                $img->SetLineWeight($this->day->grid->iWeight);
808
                $img->Line($x, $yt, $x, $yb);
809
                $this->day->grid->Stroke($img, $x, $yb, $x, $img->height - $img->bottom_margin);
810
                $datestamp = mktime(0, 0, 0, date("m", $datestamp), date("d", $datestamp) + 1, date("Y", $datestamp));
811
                //$datestamp += SECPERDAY;
812
            }
813
            $img->SetColor($this->day->iFrameColor);
814
            $img->SetLineWeight($this->day->iFrameWeight);
815
            $img->Rectangle($xt, $yt, $xb, $yb);
816
            return $yb - $img->top_margin;
817
        }
818
        return $aYCoord;
819
    }
820
821
    // Stroke week header and grid
822
    public function StrokeWeeks($aYCoord, $getHeight = false)
823
    {
824
        if ($this->week->iShowLabels) {
825
            $img = $this->iImg;
826
            $yt  = $aYCoord + $img->top_margin;
827
            $img->SetFont($this->week->iFFamily, $this->week->iFStyle, $this->week->iFSize);
828
            $yb = $yt + $img->GetFontHeight() + $this->week->iTitleVertMargin + $this->week->iFrameWeight;
829
830
            if ($getHeight) {
831
                return $yb - $img->top_margin;
832
            }
833
834
            $xt        = $img->left_margin + $this->iLabelWidth;
835
            $weekwidth = $this->GetDayWidth() * 7;
836
            $wdays     = $this->iDateLocale->GetDayAbb();
0 ignored issues
show
Unused Code introduced by
$wdays is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
837
            $xb        = $img->width - $img->right_margin + 1;
838
            $week      = $this->iStartDate;
839
            $weeknbr   = $this->GetWeekNbr($week);
840
            $img->SetColor($this->week->iBackgroundColor);
841
            $img->FilledRectangle($xt, $yt, $xb, $yb);
842
            $img->SetColor($this->week->grid->iColor);
843
            $x = $xt;
844
            if ($this->week->iStyle == WEEKSTYLE_WNBR) {
845
                $img->SetTextAlign("center");
846
                $txtOffset = $weekwidth / 2 + 1;
847
            } elseif ($this->week->iStyle == WEEKSTYLE_FIRSTDAY ||
848
                $this->week->iStyle == WEEKSTYLE_FIRSTDAY2 ||
849
                $this->week->iStyle == WEEKSTYLE_FIRSTDAYWNBR ||
850
                $this->week->iStyle == WEEKSTYLE_FIRSTDAY2WNBR) {
851
                $img->SetTextAlign("left");
852
                $txtOffset = 3;
853
            } else {
854
                Util\JpGraphError::RaiseL(6021);
855
                //("Unknown formatting style for week.");
856
            }
857
858
            for ($i = 0; $i < $this->GetNumberOfDays() / 7; ++$i, $x += $weekwidth) {
859
                $img->PushColor($this->week->iTextColor);
860
861
                if ($this->week->iStyle == WEEKSTYLE_WNBR) {
862
                    $txt = sprintf($this->week->iLabelFormStr, $weeknbr);
863
                } elseif ($this->week->iStyle == WEEKSTYLE_FIRSTDAY ||
864
                    $this->week->iStyle == WEEKSTYLE_FIRSTDAYWNBR) {
865
                    $txt = date("j/n", $week);
866
                } elseif ($this->week->iStyle == WEEKSTYLE_FIRSTDAY2 ||
867
                    $this->week->iStyle == WEEKSTYLE_FIRSTDAY2WNBR) {
868
                    $monthnbr   = date("n", $week) - 1;
869
                    $shortmonth = $this->iDateLocale->GetShortMonthName($monthnbr);
870
                    $txt        = Date("j", $week) . " " . $shortmonth;
871
                }
872
873
                if ($this->week->iStyle == WEEKSTYLE_FIRSTDAYWNBR ||
874
                    $this->week->iStyle == WEEKSTYLE_FIRSTDAY2WNBR) {
875
                    $w = sprintf($this->week->iLabelFormStr, $weeknbr);
876
                    $txt .= ' ' . $w;
0 ignored issues
show
Bug introduced by
The variable $txt 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...
877
                }
878
879
                $img->StrokeText(round($x + $txtOffset),
0 ignored issues
show
Bug introduced by
The variable $txtOffset 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...
880
                    round($yb - $this->week->iTitleVertMargin), $txt);
881
882
                $week    = strtotime('+7 day', $week);
883
                $weeknbr = $this->GetWeekNbr($week);
884
                $img->PopColor();
885
                $img->SetLineWeight($this->week->grid->iWeight);
886
                $img->Line($x, $yt, $x, $yb);
887
                $this->week->grid->Stroke($img, $x, $yb, $x, $img->height - $img->bottom_margin);
888
            }
889
            $img->SetColor($this->week->iFrameColor);
890
            $img->SetLineWeight($this->week->iFrameWeight);
891
            $img->Rectangle($xt, $yt, $xb, $yb);
892
            return $yb - $img->top_margin;
893
        }
894
        return $aYCoord;
895
    }
896
897
    // Format the mont scale header string
898
    public function GetMonthLabel($aMonthNbr, $year)
899
    {
900
        $sn = $this->iDateLocale->GetShortMonthName($aMonthNbr);
901
        $ln = $this->iDateLocale->GetLongMonthName($aMonthNbr);
902
        switch ($this->month->iStyle) {
903
            case MONTHSTYLE_SHORTNAME:
904
                $m = $sn;
905
                break;
906
            case MONTHSTYLE_LONGNAME:
907
                $m = $ln;
908
                break;
909
            case MONTHSTYLE_SHORTNAMEYEAR2:
910
                $m = $sn . " '" . substr("" . $year, 2);
911
                break;
912
            case MONTHSTYLE_SHORTNAMEYEAR4:
913
                $m = $sn . " " . $year;
914
                break;
915
            case MONTHSTYLE_LONGNAMEYEAR2:
916
                $m = $ln . " '" . substr("" . $year, 2);
917
                break;
918
            case MONTHSTYLE_LONGNAMEYEAR4:
919
                $m = $ln . " " . $year;
920
                break;
921
            case MONTHSTYLE_FIRSTLETTER:
922
                $m = $sn[0];
923
                break;
924
        }
925
        return $m;
0 ignored issues
show
Bug introduced by
The variable $m 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...
926
    }
927
928
    // Stroke month scale and gridlines
929
    public function StrokeMonths($aYCoord, $getHeight = false)
930
    {
931
        if ($this->month->iShowLabels) {
932
            $img = $this->iImg;
933
            $img->SetFont($this->month->iFFamily, $this->month->iFStyle, $this->month->iFSize);
934
            $yt = $aYCoord + $img->top_margin;
935
            $yb = $yt + $img->GetFontHeight() + $this->month->iTitleVertMargin + $this->month->iFrameWeight;
936
            if ($getHeight) {
937
                return $yb - $img->top_margin;
938
            }
939
            $monthnbr = $this->GetMonthNbr($this->iStartDate) - 1;
940
            $xt       = $img->left_margin + $this->iLabelWidth;
941
            $xb       = $img->width - $img->right_margin + 1;
942
943
            $img->SetColor($this->month->iBackgroundColor);
944
            $img->FilledRectangle($xt, $yt, $xb, $yb);
945
946
            $img->SetLineWeight($this->month->grid->iWeight);
947
            $img->SetColor($this->month->iTextColor);
948
            $year = 0 + strftime("%Y", $this->iStartDate);
949
            $img->SetTextAlign("center");
950
            if ($this->GetMonthNbr($this->iStartDate) == $this->GetMonthNbr($this->iEndDate)
951
                && $this->GetYear($this->iStartDate) == $this->GetYear($this->iEndDate)) {
952
                $monthwidth = $this->GetDayWidth() * ($this->GetMonthDayNbr($this->iEndDate) - $this->GetMonthDayNbr($this->iStartDate) + 1);
953
            } else {
954
                $monthwidth = $this->GetDayWidth() * ($this->GetNumDaysInMonth($monthnbr, $year) - $this->GetMonthDayNbr($this->iStartDate) + 1);
955
            }
956
            // Is it enough space to stroke the first month?
957
            $monthName = $this->GetMonthLabel($monthnbr, $year);
958 View Code Duplication
            if ($monthwidth >= 1.2 * $img->GetTextWidth($monthName)) {
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...
959
                $img->SetColor($this->month->iTextColor);
960
                $img->StrokeText(round($xt + $monthwidth / 2 + 1),
961
                    round($yb - $this->month->iTitleVertMargin),
962
                    $monthName);
963
            }
964
            $x = $xt + $monthwidth;
965
            while ($x < $xb) {
966
                $img->SetColor($this->month->grid->iColor);
967
                $img->Line($x, $yt, $x, $yb);
968
                $this->month->grid->Stroke($img, $x, $yb, $x, $img->height - $img->bottom_margin);
969
                $monthnbr++;
970
                if ($monthnbr == 12) {
971
                    $monthnbr = 0;
972
                    $year++;
973
                }
974
                $monthName  = $this->GetMonthLabel($monthnbr, $year);
975
                $monthwidth = $this->GetDayWidth() * $this->GetNumDaysInMonth($monthnbr, $year);
976
                if ($x + $monthwidth < $xb) {
977
                    $w = $monthwidth;
978
                } else {
979
                    $w = $xb - $x;
980
                }
981
982 View Code Duplication
                if ($w >= 1.2 * $img->GetTextWidth($monthName)) {
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...
983
                    $img->SetColor($this->month->iTextColor);
984
                    $img->StrokeText(round($x + $w / 2 + 1),
985
                        round($yb - $this->month->iTitleVertMargin), $monthName);
986
                }
987
                $x += $monthwidth;
988
            }
989
            $img->SetColor($this->month->iFrameColor);
990
            $img->SetLineWeight($this->month->iFrameWeight);
991
            $img->Rectangle($xt, $yt, $xb, $yb);
992
            return $yb - $img->top_margin;
993
        }
994
        return $aYCoord;
995
    }
996
997
    // Stroke year scale and gridlines
998
    public function StrokeYears($aYCoord, $getHeight = false)
999
    {
1000
        if ($this->year->iShowLabels) {
1001
            $img = $this->iImg;
1002
            $yt  = $aYCoord + $img->top_margin;
1003
            $img->SetFont($this->year->iFFamily, $this->year->iFStyle, $this->year->iFSize);
1004
            $yb = $yt + $img->GetFontHeight() + $this->year->iTitleVertMargin + $this->year->iFrameWeight;
1005
1006
            if ($getHeight) {
1007
                return $yb - $img->top_margin;
1008
            }
1009
1010
            $xb   = $img->width - $img->right_margin + 1;
1011
            $xt   = $img->left_margin + $this->iLabelWidth;
1012
            $year = $this->GetYear($this->iStartDate);
1013
            $img->SetColor($this->year->iBackgroundColor);
1014
            $img->FilledRectangle($xt, $yt, $xb, $yb);
1015
            $img->SetLineWeight($this->year->grid->iWeight);
1016
            $img->SetTextAlign("center");
1017
            if ($year == $this->GetYear($this->iEndDate)) {
1018
                $yearwidth = $this->GetDayWidth() * ($this->GetYearDayNbr($this->iEndDate) - $this->GetYearDayNbr($this->iStartDate) + 1);
1019
            } else {
1020
                $yearwidth = $this->GetDayWidth() * ($this->GetNumDaysInYear($year) - $this->GetYearDayNbr($this->iStartDate) + 1);
1021
            }
1022
1023
            // The space for a year must be at least 20% bigger than the actual text
1024
            // so we allow 10% margin on each side
1025 View Code Duplication
            if ($yearwidth >= 1.20 * $img->GetTextWidth("" . $year)) {
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...
1026
                $img->SetColor($this->year->iTextColor);
1027
                $img->StrokeText(round($xt + $yearwidth / 2 + 1),
1028
                    round($yb - $this->year->iTitleVertMargin),
1029
                    $year);
1030
            }
1031
            $x = $xt + $yearwidth;
1032
            while ($x < $xb) {
1033
                $img->SetColor($this->year->grid->iColor);
1034
                $img->Line($x, $yt, $x, $yb);
1035
                $this->year->grid->Stroke($img, $x, $yb, $x, $img->height - $img->bottom_margin);
1036
                $year += 1;
1037
                $yearwidth = $this->GetDayWidth() * $this->GetNumDaysInYear($year);
1038
                if ($x + $yearwidth < $xb) {
1039
                    $w = $yearwidth;
1040
                } else {
1041
                    $w = $xb - $x;
1042
                }
1043
1044 View Code Duplication
                if ($w >= 1.2 * $img->GetTextWidth("" . $year)) {
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...
1045
                    $img->SetColor($this->year->iTextColor);
1046
                    $img->StrokeText(round($x + $w / 2 + 1),
1047
                        round($yb - $this->year->iTitleVertMargin),
1048
                        $year);
1049
                }
1050
                $x += $yearwidth;
1051
            }
1052
            $img->SetColor($this->year->iFrameColor);
1053
            $img->SetLineWeight($this->year->iFrameWeight);
1054
            $img->Rectangle($xt, $yt, $xb, $yb);
1055
            return $yb - $img->top_margin;
1056
        }
1057
        return $aYCoord;
1058
    }
1059
1060
    // Stroke table title (upper left corner)
1061
    public function StrokeTableHeaders($aYBottom)
1062
    {
1063
        $img = $this->iImg;
1064
        $xt  = $img->left_margin;
1065
        $yt  = $img->top_margin;
1066
        $xb  = $xt + $this->iLabelWidth;
1067
        $yb  = $aYBottom + $img->top_margin;
1068
1069
        if ($this->tableTitle->iShow) {
1070
            $img->SetColor($this->iTableHeaderBackgroundColor);
1071
            $img->FilledRectangle($xt, $yt, $xb, $yb);
1072
            $this->tableTitle->Align("center", "top");
1073
            $this->tableTitle->Stroke($img, $xt + ($xb - $xt) / 2 + 1, $yt + 2);
1074
            $img->SetColor($this->iTableHeaderFrameColor);
1075
            $img->SetLineWeight($this->iTableHeaderFrameWeight);
1076
            $img->Rectangle($xt, $yt, $xb, $yb);
1077
        }
1078
1079
        $this->actinfo->Stroke($img, $xt, $yt, $xb, $yb, $this->tableTitle->iShow);
1080
1081
        // Draw the horizontal dividing line
1082
        $this->dividerh->Stroke($img, $xt, $yb, $img->width - $img->right_margin, $yb);
1083
1084
        // Draw the vertical dividing line
1085
        // We do the width "manually" since we want the line only to grow
1086
        // to the left
1087
        $fancy = $this->divider->iStyle == 'fancy';
1088
        if ($fancy) {
1089
            $this->divider->iStyle = 'solid';
1090
        }
1091
1092
        $tmp                    = $this->divider->iWeight;
1093
        $this->divider->iWeight = 1;
1094
        $y                      = $img->height - $img->bottom_margin;
1095
        for ($i = 0; $i < $tmp; ++$i) {
1096
            $this->divider->Stroke($img, $xb - $i, $yt, $xb - $i, $y);
1097
        }
1098
1099
        // Should we draw "fancy" divider
1100
        if ($fancy) {
1101
            $img->SetLineWeight(1);
1102
            $img->SetColor($this->iTableHeaderFrameColor);
1103
            $img->Line($xb, $yt, $xb, $y);
1104
            $img->Line($xb - $tmp + 1, $yt, $xb - $tmp + 1, $y);
1105
            $img->SetColor('white');
1106
            $img->Line($xb - $tmp + 2, $yt, $xb - $tmp + 2, $y);
1107
        }
1108
    }
1109
1110
    // Main entry point to stroke scale
1111
    public function Stroke()
1112
    {
1113
        if (!$this->IsRangeSet()) {
1114
            Util\JpGraphError::RaiseL(6022);
1115
            //("Gantt scale has not been specified.");
1116
        }
1117
        $img = $this->iImg;
1118
1119
        // If minutes are displayed then hour interval must be 1
1120
        if ($this->IsDisplayMinute() && $this->hour->GetIntervall() > 1) {
1121
            Util\JpGraphError::RaiseL(6023);
1122
            //('If you display both hour and minutes the hour intervall must be 1 (Otherwise it doesn\' make sense to display minutes).');
1123
        }
1124
1125
        // Stroke all headers. As argument we supply the offset from the
1126
        // top which depends on any previous headers
1127
1128
        // First find out the height of each header
1129
        $offy   = $this->StrokeYears(0, true);
1130
        $offm   = $this->StrokeMonths($offy, true);
1131
        $offw   = $this->StrokeWeeks($offm, true);
1132
        $offd   = $this->StrokeDays($offw, true);
1133
        $offh   = $this->StrokeHours($offd, true);
1134
        $offmin = $this->StrokeMinutes($offh, true);
1135
1136
        // ... then we can stroke them in the "backwards order to ensure that
1137
        // the larger scale gridlines is stroked over the smaller scale gridline
1138
        $this->StrokeMinutes($offh);
1139
        $this->StrokeHours($offd);
1140
        $this->StrokeDays($offw);
1141
        $this->StrokeWeeks($offm);
1142
        $this->StrokeMonths($offy);
1143
        $this->StrokeYears(0);
1144
1145
        // Now when we now the oaverall size of the scale headers
1146
        // we can stroke the overall table headers
1147
        $this->StrokeTableHeaders($offmin);
1148
1149
        // Now we can calculate the correct scaling factor for each vertical position
1150
        $this->iAvailableHeight = $img->height - $img->top_margin - $img->bottom_margin - $offd;
0 ignored issues
show
Documentation Bug introduced by
It seems like $img->height - $img->top...->bottom_margin - $offd can also be of type double. However, the property $iAvailableHeight is declared as type integer. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
1151
1152
        $this->iVertHeaderSize = $offmin;
1153
        if ($this->iVertSpacing == -1) {
1154
            $this->iVertSpacing = $this->iAvailableHeight / $this->iVertLines;
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->iAvailableHeight / $this->iVertLines can also be of type double. However, the property $iVertSpacing is declared as type integer. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
1155
        }
1156
    }
1157
}
1158