Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 2 additions & 6 deletions Module.php
Original file line number Diff line number Diff line change
Expand Up @@ -92,17 +92,13 @@ private static function permissionInstances(array $classes): array

public function getAdapterRegistry(): AdapterRegistry
{
if ($this->adapterRegistry === null) {
$this->adapterRegistry = AdapterRegistry::createDefault();
}
$this->adapterRegistry ??= AdapterRegistry::createDefault();
return $this->adapterRegistry;
}

public function getSpecialBetTypeRegistry(): SpecialBetTypeRegistry
{
if ($this->specialBetTypeRegistry === null) {
$this->specialBetTypeRegistry = SpecialBetTypeRegistry::createDefault();
}
$this->specialBetTypeRegistry ??= SpecialBetTypeRegistry::createDefault();
return $this->specialBetTypeRegistry;
}

Expand Down
4 changes: 1 addition & 3 deletions adapters/FootballDataOrgAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -171,9 +171,7 @@ private function syncTeams(Competition $competition, array $teamsData, SyncRepor
}
$team = Team::findByExternalId(self::KEY, $externalId);
$isNew = $team === null;
if ($team === null) {
$team = new Team();
}
$team ??= new Team();
$team->name = (string) ($teamData['name'] ?? $team->name ?? 'Unknown');
$team->short_name = $teamData['tla'] ?? $teamData['shortName'] ?? $team->short_name;
$team->country_code = $teamData['area']['code'] ?? $team->country_code;
Expand Down
4 changes: 1 addition & 3 deletions adapters/HumHubApiAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -209,9 +209,7 @@ private function applyTeams(Competition $competition, array $teamsData, SyncRepo
}
$team = Team::findByExternalId(self::KEY, $externalId);
$isNew = $team === null;
if ($team === null) {
$team = new Team();
}
$team ??= new Team();
$team->name = (string) ($teamData['name'] ?? $team->name ?? 'Unknown');
$team->short_name = $teamData['short_name'] ?? $team->short_name;
$team->country_code = $teamData['country_code'] ?? $team->country_code;
Expand Down
12 changes: 5 additions & 7 deletions adapters/MockAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -124,13 +124,13 @@ public function syncResults(Competition $competition): SyncReport
foreach ($scheduled as $game) {
$elapsed = $now - (KickoffTime::parse($game->kickoff_at) ?? $now);
if ($elapsed > self::LIVE_WINDOW_SEC) {
$game->home_score = $game->home_score ?? random_int(0, 4);
$game->away_score = $game->away_score ?? random_int(0, 4);
$game->home_score ??= random_int(0, 4);
$game->away_score ??= random_int(0, 4);
$game->status = Game::STATUS_FINISHED;
$game->current_minute = null;
} else {
$game->home_score = $game->home_score ?? 0;
$game->away_score = $game->away_score ?? 0;
$game->home_score ??= 0;
$game->away_score ??= 0;
$game->status = Game::STATUS_LIVE;
$game->current_minute = $this->mockMatchMinute($elapsed);
}
Expand Down Expand Up @@ -404,9 +404,7 @@ protected function computeGroupStandings(Competition $competition): array
foreach ($games as $g) {
$group = (string) $g->group_label;
foreach ([$g->home_team_id, $g->away_team_id] as $tid) {
if (!isset($stats[$group][$tid])) {
$stats[$group][$tid] = ['points' => 0, 'diff' => 0, 'for' => 0];
}
$stats[$group][$tid] ??= ['points' => 0, 'diff' => 0, 'for' => 0];
}
$hs = (int) $g->home_score;
$as = (int) $g->away_score;
Expand Down
12 changes: 5 additions & 7 deletions controllers/CompetitionController.php
Original file line number Diff line number Diff line change
Expand Up @@ -217,11 +217,9 @@ private function shouldDefaultToBonus(array $openSpecialBets, int $userId): bool

private function pickDefaultMatchday(array $entries): ?string
{
$isDated = function (array $entry): bool {
return $entry['games'] !== []
&& empty($entry['isPlaceholder'])
&& empty($entry['isBonus']);
};
$isDated = (fn(array $entry): bool => $entry['games'] !== []
&& empty($entry['isPlaceholder'])
&& empty($entry['isBonus']));

// Earliest matchday that still has at least one game whose kickoff is
// in the future — i.e. the next-best one the user can still tip.
Expand Down Expand Up @@ -382,7 +380,7 @@ public function actionUserHistory($slug, $userId, $page = 1)
$page = max(1, (int) $page);

$baseTipQuery = Tip::find()
->joinWith(['game' => function ($q) use ($competition) {
->joinWith(['game' => function ($q) use ($competition): void {
$q->andWhere(['kickoff_game.competition_id' => $competition->id]);
}])
->andWhere(['user_id' => $targetUserId])
Expand All @@ -408,7 +406,7 @@ public function actionUserHistory($slug, $userId, $page = 1)
// Weltmeister/group-winner tip — the view filters by points in PHP, but
// defense in depth says filter at the source.
$specialBetTips = SpecialBetTip::find()
->joinWith(['specialBet' => function ($q) use ($competition) {
->joinWith(['specialBet' => function ($q) use ($competition): void {
$q->andWhere(['kickoff_special_bet.competition_id' => $competition->id]);
}])
->andWhere(['user_id' => $targetUserId])
Expand Down
4 changes: 4 additions & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
Changelog
=========

1.0.17 (Unreleased)
-------------------
- Enh: Automated code refactoring for HumHub 1.18 using Rector

1.0.16 (June 30, 2026)
----------------------
- Fix: Knockout matches decided in extra time or a penalty shootout were scored and shown against the wrong result. football-data.org's `fullTime` score is the cumulative final — it already includes extra-time goals and the penalty shootout — and is not the score after 90 minutes, so with the default "after 90 minutes" knockout scoring tips were wrongly scored against the extra-time/penalty result. The 90-minute score (the API's `regularTime`) is now used for scoring, the end-of-extra-time score is stored correctly (previously it held only the goals scored within extra time), and existing games are re-synced automatically on the next hourly cron after the update — no manual sync needed.
Expand Down
6 changes: 3 additions & 3 deletions module.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"world cup",
"leaderboard"
],
"version": "1.0.16",
"version": "1.0.17",
"humhub": {
"minVersion": "1.18"
},
Expand All @@ -20,7 +20,7 @@
"name": "Lucas Bartholemy"
},
{
"name": "Jörg Winne"
"name": "J\u00f6rg Winne"
}
],
"screenshots": [
Expand All @@ -32,4 +32,4 @@
"resources/screen6.png",
"resources/screen7.png"
]
}
}
4 changes: 1 addition & 3 deletions services/GroupStandings.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,7 @@ public static function ranked(array $results): array
$stats = [];
foreach ($results as $r) {
foreach ([$r['home'], $r['away']] as $tid) {
if (!isset($stats[$tid])) {
$stats[$tid] = ['teamId' => $tid, 'points' => 0, 'diff' => 0, 'for' => 0];
}
$stats[$tid] ??= ['teamId' => $tid, 'points' => 0, 'diff' => 0, 'for' => 0];
}
$hs = (int) $r['homeScore'];
$as = (int) $r['awayScore'];
Expand Down
4 changes: 2 additions & 2 deletions services/LeaderboardService.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@

class LeaderboardService
{
private Competition $competition;
private ScoringScheme $scheme;
private readonly Competition $competition;
private readonly ScoringScheme $scheme;

public function __construct(Competition $competition)
{
Expand Down
9 changes: 3 additions & 6 deletions services/MatchdayBonusService.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,11 @@
class MatchdayBonusService
{
public const BUCKET_BONUS = 'bonus';
private readonly int $bonusPoints;

private Competition $competition;
private int $bonusPoints;

public function __construct(Competition $competition)
public function __construct(private readonly Competition $competition)
{
$this->competition = $competition;
$scheme = $competition->scoringScheme;
$scheme = $this->competition->scoringScheme;
$this->bonusPoints = $scheme !== null ? (int) $scheme->matchday_winner_points : 0;
}

Expand Down
4 changes: 2 additions & 2 deletions services/ScoringService.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@

class ScoringService
{
private Competition $competition;
private ScoringScheme $scheme;
private readonly Competition $competition;
private readonly ScoringScheme $scheme;

public function __construct(Competition $competition)
{
Expand Down
4 changes: 2 additions & 2 deletions views/competition/_detail_modal.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* Reused for user-history, match-tips and their pagination links.
*/

$modalJs = <<<JS
$modalJs = <<<JS_WRAP
(function (\$) {
\$(function () {
var modalEl = document.getElementById('kickoff-detail-modal');
Expand Down Expand Up @@ -59,7 +59,7 @@ function relocatePreview() {
});
});
})(jQuery);
JS;
JS_WRAP;
// Unique key so this <script> block is emitted at most once even if the partial
// gets rendered twice in a single page (e.g. nested layouts).
$this->registerJs($modalJs, \yii\web\View::POS_END, 'kickoff-detail-modal');
Expand Down
6 changes: 3 additions & 3 deletions views/competition/_match_card.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
/** @var \humhub\modules\kickoff\models\Competition $competition */
/** @var bool $preview Render only the part above the footer (no dashed-line footer). */

$preview = $preview ?? false;
$preview ??= false;

$home = $game->homeTeam;
$away = $game->awayTeam;
Expand All @@ -30,8 +30,8 @@
$displayHomeScore = $ruleScore[0] ?? $game->home_score;
$displayAwayScore = $ruleScore[1] ?? $game->away_score;
if ($isLive) {
$displayHomeScore = $displayHomeScore ?? 0;
$displayAwayScore = $displayAwayScore ?? 0;
$displayHomeScore ??= 0;
$displayAwayScore ??= 0;
}
$hasDisplayScore = $displayHomeScore !== null && $displayAwayScore !== null;
// Live and finished games both render the score in a big, prominent block
Expand Down
12 changes: 5 additions & 7 deletions views/competition/rules.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,11 @@

$this->registerAssetBundle(\humhub\modules\kickoff\assets\Assets::class);

$specialBetTypeLabel = function (string $type): string {
return match ($type) {
SpecialBet::TYPE_WINNER => Yii::t('KickoffModule.base', 'Tournament winner'),
SpecialBet::TYPE_GROUP_WINNER => Yii::t('KickoffModule.base', 'Group winner'),
default => ucfirst($type),
};
};
$specialBetTypeLabel = (fn(string $type): string => match ($type) {
SpecialBet::TYPE_WINNER => Yii::t('KickoffModule.base', 'Tournament winner'),
SpecialBet::TYPE_GROUP_WINNER => Yii::t('KickoffModule.base', 'Group winner'),
default => ucfirst($type),
});

?>
<div class="container">
Expand Down