CampaignConfigurationLoader::__construct()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 2
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare( strict_types = 1 );
4
5
namespace WMDE\BannerServer\Utils;
6
7
use Symfony\Component\Yaml\Yaml;
8
use WMDE\BannerServer\Entity\BannerSelection\Banner;
9
use WMDE\BannerServer\Entity\BannerSelection\Bucket;
10
use WMDE\BannerServer\Entity\BannerSelection\Campaign;
11
use WMDE\BannerServer\Entity\BannerSelection\CampaignCollection;
12
use WMDE\BannerServer\InvalidConfigurationValueException;
13
14
/**
15
 * @license GPL-2.0-or-later
16
 */
17
class CampaignConfigurationLoader {
18
19
	private string $configFile;
20
21 7
	public function __construct( string $configFile ) {
22 7
		$this->configFile = $configFile;
23
	}
24
25 7
	public function getCampaignCollection(): CampaignCollection {
26 7
		$campaigns = [];
27 7
		foreach ( $this->parseConfiguration() as $campaignName => $campaignData ) {
28 6
				$campaign = $this->buildCampaignFromData( $campaignName, $campaignData );
29 2
				$campaigns[] = $campaign;
30
		}
31 2
		return new CampaignCollection( ...$campaigns );
32
	}
33
34 6
	private function buildCampaignFromData( string $campaignName, array $campaignData ): Campaign {
35 6
		$buckets = $this->buildBucketsFromData( $campaignData );
36 4
		if ( empty( $buckets ) ) {
37
			throw new InvalidConfigurationValueException( 'Campaign contains no buckets.' );
38
		}
39 4
		if ( empty( $campaignData['start'] ) || empty( $campaignData['end'] ) || !isset( $campaignData['trafficLimit'] ) ) {
40 1
			throw new InvalidConfigurationValueException( 'Campaign data is incomplete.' );
41
		}
42 3
		$minDisplayWidth = $this->integerOrNullValue( $campaignData, 'minDisplayWidth' );
43 3
		$maxDisplayWidth = $this->integerOrNullValue( $campaignData, 'maxDisplayWidth' );
44 3
		if ( $minDisplayWidth && $maxDisplayWidth && $minDisplayWidth > $maxDisplayWidth ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $maxDisplayWidth of type integer|null is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== null instead.

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

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
Bug Best Practice introduced by
The expression $minDisplayWidth of type integer|null is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== null instead.

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

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
45 1
			throw new InvalidConfigurationValueException(
46 1
				'Campaign data display width values are invalid (if defined, max must be higher than min).'
47 1
			);
48
		}
49 2
		return new Campaign(
50 2
			$campaignName,
51 2
			new \DateTime( $campaignData['start'] ),
52 2
			new \DateTime( $campaignData['end'] ),
53 2
			(int)$campaignData['trafficLimit'],
54 2
			$campaignData['category'] ?? 'default',
55 2
			new SystemRandomIntegerGenerator(),
56 2
			$minDisplayWidth,
57 2
			$maxDisplayWidth,
58 2
			array_shift( $buckets ),
59 2
			...$buckets
60 2
		);
61
	}
62
63 6
	private function buildBucketsFromData( array $campaignData ): array {
64 6
		$buckets = [];
65 6
		foreach ( $campaignData['buckets'] as $bucketData ) {
66 6
			$bucket = $this->buildBucketFromData( $bucketData );
67 4
			$buckets[] = $bucket;
68
		}
69 4
		return $buckets;
70
	}
71
72 6
	private function buildBucketFromData( array $bucketData ): Bucket {
73 6
		if ( !isset( $bucketData['name'] ) ) {
74 1
			throw new InvalidConfigurationValueException( 'A configured bucket has no name.' );
75
		}
76 5
		if ( !isset( $bucketData['banners'] ) ) {
77 1
			throw new InvalidConfigurationValueException( 'A configured bucket has no associated banners.' );
78
		}
79 4
		$banners = $this->buildBannersFromData( $bucketData['banners'] );
80 4
		if ( empty( $banners ) ) {
81
			throw new InvalidConfigurationValueException( 'A configured bucket has no valid banners associated with it.' );
82
		}
83 4
		return new Bucket( $bucketData['name'], array_shift( $banners ), ...$banners );
84
	}
85
86 4
	private function buildBannersFromData( array $bannerData ): array {
87 4
		$banners = [];
88 4
		foreach ( $bannerData as $bannerIdentifier ) {
89 4
			if ( !$bannerIdentifier ) {
90
				throw new InvalidConfigurationValueException( 'A configured banner has an empty name.' );
91
			}
92 4
			$banners[] = new Banner( $bannerIdentifier );
93
		}
94 4
		return $banners;
95
	}
96
97 7
	private function parseConfiguration(): array {
98 7
		return Yaml::parseFile( $this->configFile );
99
	}
100
101 3
	private function integerOrNullValue( array $campaignData, string $key ): ?int {
102 3
		if ( !isset( $campaignData[$key] ) ) {
103 2
			return null;
104
		}
105 3
		$value = $campaignData[$key];
106 3
		if ( !is_numeric( $value ) ) {
107
			return null;
108
		}
109 3
		return intval( $value );
110
	}
111
}
112