Completed
Push — feature/new-tests ( d030dc )
by brian
01:56
created

AbstractPreferenceBuilder::validQualityFactor()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 3

Importance

Changes 0
Metric Value
dl 0
loc 4
c 0
b 0
f 0
ccs 2
cts 2
cp 1
rs 10
cc 3
nc 3
nop 1
crap 3
1
<?php declare(strict_types = 1);
2
3
/**
4
 * @copyright   (c) 2006-present brian ridley
5
 * @author      brian ridley <[email protected]>
6
 * @license     http://opensource.org/licenses/MIT MIT
7
 */
8
9
namespace ptlis\ConNeg\Preference\Builder;
10
11
use ptlis\ConNeg\Exception\InvalidVariantException;
12
13
/**
14
 * Shared preference building implementation.
15
 */
16
abstract class AbstractPreferenceBuilder implements PreferenceBuilderInterface
17
{
18
    /**
19
     * @var bool
20
     */
21
    protected $isFromServer = false;
22
23
    /**
24
     * @var string
25
     */
26
    protected $fromField;
27
28
    /**
29
     * @var string
30
     */
31
    protected $variant = '';
32
33
    /**
34
     * @var float
35
     */
36
    protected $qFactor = 1;
37
38
39
    /**
40
     * @inheritDoc
41
     */
42 93
    public function setFromServer(bool $isFromServer): PreferenceBuilderInterface
43
    {
44 93
        $clone = clone $this;
45 93
        $clone->isFromServer = $isFromServer;
46
47 93
        return $clone;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $clone; (ptlis\ConNeg\Preference\...stractPreferenceBuilder) is incompatible with the return type declared by the interface ptlis\ConNeg\Preference\...nterface::setFromServer of type self.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

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

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
48
    }
49
50
    /**
51
     * @inheritDoc
52
     */
53 100
    public function setFromField(string $fromField): PreferenceBuilderInterface
54
    {
55 100
        $clone = clone $this;
56 100
        $clone->fromField = $fromField;
57
58 100
        return $clone;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $clone; (ptlis\ConNeg\Preference\...stractPreferenceBuilder) is incompatible with the return type declared by the interface ptlis\ConNeg\Preference\...Interface::setFromField of type self.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

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

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
59
    }
60
61
    /**
62
     * @inheritDoc
63
     *
64
     * @throws InvalidVariantException If the provided variant is not valid.
65
     */
66 93
    public function setVariant(string $variant): PreferenceBuilderInterface
67
    {
68 93
        if ($this->isFromServer) {
69 73
            $this->validateVariant($variant);
70
        }
71
72 90
        $clone = clone $this;
73 90
        $clone->variant = $this->normalizeVariant($variant);
74
75 90
        return $clone;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $clone; (ptlis\ConNeg\Preference\...stractPreferenceBuilder) is incompatible with the return type declared by the interface ptlis\ConNeg\Preference\...erInterface::setVariant of type self.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

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

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
76
    }
77
78
    /**
79
     * @inheritDoc
80
     *
81
     * @throws InvalidVariantException If an invalid quality factor in encountered when building an server preference.
82
     */
83 88
    public function setQualityFactor(float $qFactor): PreferenceBuilderInterface
84
    {
85 88
        if ($this->isFromServer && !$this->validQualityFactor($qFactor)) {
86 2
            throw new InvalidVariantException('Invalid quality factor "' . $qFactor . '" in server preferences');
87
        }
88
89 86
        $qFactor = $this->normalizeQualityFactor($qFactor);
90
91 86
        $clone = clone $this;
92 86
        $clone->qFactor = $qFactor;
93
94 86
        return $clone;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $clone; (ptlis\ConNeg\Preference\...stractPreferenceBuilder) is incompatible with the return type declared by the interface ptlis\ConNeg\Preference\...rface::setQualityFactor of type self.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

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

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
95
    }
96
97
    /**
98
     * Validate the variant, returning true if the variant is valid.
99
     *
100
     * @throws InvalidVariantException If the provided variant is not valid.
101
     *
102
     * @param string $variant
103
     */
104
    abstract protected function validateVariant(string $variant): void;
105
106
    /**
107
     * Normalises the variant.
108
     *
109
     * @param string $variant
110
     *
111
     * @return string
112
     */
113 54
    protected function normalizeVariant(string $variant): string
114
    {
115 54
        return $variant;
116
    }
117
118
    /**
119
     * Validate the quality factor, returning true if the quality factor is valid.
120
     *
121
     * @param float $qFactor
122
     *
123
     * @return bool
124
     */
125 50
    private function validQualityFactor(float $qFactor): bool
126
    {
127 50
        return is_numeric($qFactor) && $qFactor >= 0 && $qFactor <= 1;
128
    }
129
130
    /**
131
     * Normalises the provided quality factor, ensuring that the value returned is a float between 0 and 1 (inclusive).
132
     *
133
     * @param float $qFactor
134
     *
135
     * @return float
136
     */
137 86
    private function normalizeQualityFactor(float $qFactor): float
138
    {
139 86
        if (!is_numeric($qFactor)) {
140
            $qFactor = 1.0;
141
0 ignored issues
show
Coding Style introduced by
Blank line found at end of control structure
Loading history...
142 86
        } elseif ($qFactor < 0) {
143 1
            $qFactor = 0.0;
144
0 ignored issues
show
Coding Style introduced by
Blank line found at end of control structure
Loading history...
145 85
        } elseif ($qFactor > 1) {
146 1
            $qFactor = 1.0;
147
0 ignored issues
show
Coding Style introduced by
Blank line found at end of control structure
Loading history...
148
        } else {
149 84
            $qFactor = floatval($qFactor);
150
        }
151
152 86
        return $qFactor;
153
    }
154
}
155