DevelopingFactory::extractTime()   B
last analyzed

Complexity

Conditions 8
Paths 7

Size

Total Lines 27

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 17
CRAP Score 8

Importance

Changes 0
Metric Value
dl 0
loc 27
ccs 17
cts 17
cp 1
rs 8.4444
c 0
b 0
f 0
cc 8
nc 7
nop 1
crap 8
1
<?php
2
namespace FilmTools\Developing;
3
4
use FilmTools\Commons\Zones;
5
use FilmTools\Commons\FStops;
6
use FilmTools\Commons\Exposures;
7
use FilmTools\Commons\ExposuresProviderInterface;
8
use FilmTools\Commons\Densities;
9
use FilmTools\Commons\DensitiesProviderInterface;
10
11
class DevelopingFactory
12
{
13
14
    /**
15
     * PHP class name (FQDN) of the DevelopingInterface instance this factory produces.
16
     *
17
     * @var string
18
     */
19
    public $developing_php_class;
20
21
22
    /**
23
     * Field names that may contain density values.
24
     * (Sort order from "most" to "least" specific)
25
     *
26
     * @var array
27
     */
28
    public $density_fields = array("logD", "density", "densities");
29
30
31
    /**
32
     * Field names that may contain exposures values.
33
     * (Sort order from "most" to "least" specific)
34
     *
35
     * @var array
36
     */
37
    public $exposure_fields = array("logH", "exposure", "exposures");
38
39
40
    /**
41
     * @param string|null $developing_php_class DevelopingInterface instance FQDN
42
     *
43
     * @throws InvalidArgumentException If FQDN does not implement DevelopingInterface
44
     */
45 51
    public function __construct( string $developing_php_class = null )
46
    {
47 51
        $this->developing_php_class = $developing_php_class ?: Developing::class;
48
49 51
        if (!is_subclass_of($this->developing_php_class, DevelopingInterface::class )):
0 ignored issues
show
Bug introduced by
Due to PHP Bug #53727, is_subclass_of might return inconsistent results on some PHP versions if \FilmTools\Developing\DevelopingInterface::class can be an interface. If so, you could instead use ReflectionClass::implementsInterface.
Loading history...
50 3
            $msg = sprintf("Class name must implement '%s'.", DevelopingInterface::class);
51 3
            throw new DevelopingInvalidArgumentException( $msg );
52
        endif;
53 48
    }
54
55
56
    /**
57
     * The factory method.
58
     *
59
     * Expects an array or ArrayAccess with at least elements "time", "densities", and "exposures".
60
     *
61
     * If no "exposures" are given, but "zones" numbers are instead, the zone numbers
62
     * will be converted internally.
63
     *
64
     * @param  array|ArrayAccess $developing
65
     * @return DevelopingInterface
66
     */
67 48
    public function __invoke( $developing ) : DevelopingInterface
68
    {
69 48
        if (!is_array($developing) and !$developing instanceOf \ArrayAccess)
70 3
            throw new DevelopingInvalidArgumentException("Array or ArrayAccess expected");
71
72 45
        $densities = $this->extractDensities($developing);
73 45
        $exposures = $this->extractExposures($developing);
74 45
        $time      = $this->extractTime($developing);
75
76 24
        $developing_php_class = $this->developing_php_class;
77 24
        return new $developing_php_class( $exposures, $densities, $time );
78
    }
79
80
81 45
    protected function extractDensities( $developing ) : DensitiesProviderInterface
82
    {
83 45
        $density_fields = $this->density_fields;
84 45
        $densities = array();
85
86 45
        while (($field = array_shift($density_fields)) and empty($densities)):
87 45
            $densities = $developing[ $field ] ?? array();
88
        endwhile;
89
90 45
        return new Densities($densities);
91
    }
92
93
94 45
    protected function extractExposures( $developing ) : ExposuresProviderInterface
95
    {
96
97 45
        $exposure_fields = $this->exposure_fields;
98 45
        $exposures = array();
99
100 45
        while (($field = array_shift($exposure_fields)) and empty($exposures)):
101 45
            $exposures = $developing[ $field ] ?? array();
102
        endwhile;
103
104 45
        if (!empty($exposures)):
105 3
            return new Exposures( $exposures );
106
        endif;
107
108
        // So if "exposures" are empty, try to make some
109
        // using fstops and zone numbers
110 42
        $fstops = ($developing['fstop'] ?? array()) ?: $developing['fstops'] ?? array();
111 42
        $zones  = ($developing['zone']  ?? array()) ?: $developing['zones']  ?? array();
112
113 42
        if (empty($exposures) and !empty($zones)):
114 30
            $exposures = new Zones( $zones );
115 12
        elseif (empty($exposures) and !empty($fstops)):
116 3
            $exposures = new FStops( $fstops );
117
        else:
118
            // Found nothing, give up
119 9
            $exposures = new Exposures( array() );
120
        endif;
121
122 42
        return $exposures;
123
    }
124
125
126 45
    protected function extractTime( $developing ) : int
127
    {
128 45
        if (!array_key_exists("time", $developing)
129 45
        and !array_key_exists("seconds", $developing))
130 3
            throw new NoTimeGivenException("The data array must contain either 'time' or 'seconds' element.");
131
132 42
        if (empty($time = $developing['seconds'] ?? false)
133 42
        and empty($time = $developing['time'] ?? false)):
134 12
            throw new NoTimeGivenException("At least one element in 'seconds' or 'time' expected");
135
        endif;
136
137
        // Remove surfluous time values
138 30
        if (is_array($time)):
139 9
            $time = array_unique($time);
140 9
            $count_times = count($time);
141 9
            if ($count_times > 1):
142 3
                $msg = sprintf("There must only be one developing time, %s given", $count_times);
143 3
                throw new NoTimeGivenException($msg);
144
            endif;
145 6
            $time = array_shift($time);
146
        endif;
147
148 27
        if (filter_var($time, \FILTER_VALIDATE_INT, ['options' => array( 'min_range' => 0 )]) === false)
149 3
            throw new NoTimeGivenException("The developing time must be integer (positive or 0).");
150
151 24
        return $time;
152
    }
153
}
154