Completed
Push — master ( 1d0973...9e97b2 )
by Hannes
02:10
created

AccountFactory::createParseMap()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 30
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 5

Importance

Changes 0
Metric Value
dl 0
loc 30
ccs 15
cts 15
cp 1
rs 8.439
c 0
b 0
f 0
cc 5
eloc 18
nc 5
nop 1
crap 5
1
<?php
2
3
namespace byrokrat\banking;
4
5
use byrokrat\banking\Rewriter\RewriterStrategy;
6
use byrokrat\banking\Rewriter\ClearingSeparatorRewriter;
7
use byrokrat\banking\Rewriter\SwedbankCheckDigitRewriter;
8
use byrokrat\banking\Exception\UnableToCreateAccountException;
9
use byrokrat\banking\Exception\InvalidAccountNumberException;
10
11
/**
12
 * Account number factory
13
 */
14
class AccountFactory
15
{
16
    /**
17
     * @var Format[] Loaded formats
18
     */
19
    private $formats;
20
21
    /**
22
     * @var RewriterStrategy[] Strategies for rewriting failing account numbers
23
     */
24
    private $rewriteStrategies;
25
26
    /**
27
     * @var bool Flag if rewrites should be allowed when creating account objects
28
     */
29
    private $allowRewrites;
30
31
    /**
32
     * @var UnknownFormat The unknown format or null if unknown is disallowed
33
     */
34
    private $unknownFormat;
35
36
    /**
37
     * @param Format[]           $formats
38
     * @param RewriterStrategy[] $rewrites
39
     * @param boolean            $allowRewrites Flag if rewrites should be allowed when creating account objects
40
     * @param boolean            $allowUnknown  Flag if the unknown account format should be used
41
     */
42 9
    public function __construct(array $formats = [], array $rewrites = [], $allowRewrites = true, $allowUnknown = true)
43
    {
44 9
        $this->formats = $formats ?: (new Formats)->createFormats();
0 ignored issues
show
Documentation Bug introduced by
It seems like $formats ?: (new \byrokr...ats())->createFormats() of type array<integer|string,obj...rokrat\banking\Format>> is incompatible with the declared type array<integer,object<byrokrat\banking\Format>> of property $formats.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
45 9
        $this->rewriteStrategies = $rewrites ?: [new ClearingSeparatorRewriter, new SwedbankCheckDigitRewriter];
46 9
        $this->allowRewrites = $allowRewrites;
47 9
        $this->unknownFormat = $allowUnknown ? new UnknownFormat : null;
48 9
    }
49
50
    /**
51
     * Enable formats
52
     *
53
     * Please note that formats not listed will be dropped and
54
     * can not be recovered.
55
     *
56
     * @param  string[] $formats List of formats to whitelist
57
     * @return null
58
     */
59 1
    public function whitelistFormats(array $formats)
60
    {
61 1
        foreach ($this->formats as $formatId => $format) {
62 1
            if (!in_array($formatId, $formats)) {
63 1
                unset($this->formats[$formatId]);
64
            }
65
        }
66 1
    }
67
68
    /**
69
     * Disable formats
70
     *
71
     * Please note that listed formats will be dropped and
72
     * can not be recovered.
73
     *
74
     * @param  string[] $formats List of formats to blacklist
75
     * @return null
76
     */
77 1
    public function blacklistFormats(array $formats)
78
    {
79 1
        foreach ($formats as $format) {
80 1
            unset($this->formats[$format]);
81
        }
82 1
    }
83
84
    /**
85
     * Create bank account object using number
86
     *
87
     * @param  string $number
88
     * @return AccountNumber
89
     * @throws UnableToCreateAccountException If unable to create
90
     */
91 9
    public function createAccount($number)
92
    {
93 9
        $parseMap = $this->createParseMap($number);
94
95 9
        if (count($parseMap['success']) == 1) {
96 3
            return $parseMap['success'][0];
97
        }
98
99 6 View Code Duplication
        if (count($parseMap['success']) > 1) {
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...
100 1
            throw new UnableToCreateAccountException(
101
                sprintf(
102 1
                    'Unable to parse account %s, multiple matching formats: %s.',
103
                    $number,
104
                    implode(
105 1
                        ' and ',
106
                        array_map(
107
                            function (AccountNumber $account) {
108 1
                                return $account->getBankName();
109 1
                            },
110 1
                            $parseMap['success']
111
                        )
112
                    )
113
                )
114
            );
115
        }
116
117 5
        if (count($parseMap['rewrite']) == 1 && $this->allowRewrites) {
118 1
            return $parseMap['rewrite'][0];
119
        }
120
121 4 View Code Duplication
        if ($parseMap['rewrite']) {
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...
122 2
            throw new UnableToCreateAccountException(
123
                sprintf(
124 2
                    'Unable to parse account %s. You may rewrite number as: %s.',
125
                    $number,
126
                    implode(
127 2
                        ' or ',
128
                        array_map(
129
                            function (AccountNumber $account) {
130 2
                                return $account->getNumber();
131 2
                            },
132 2
                            $parseMap['rewrite']
133
                        )
134
                    )
135
                )
136
            );
137
        }
138
139 2
        if ($this->unknownFormat) {
140
            try {
141 2
                return $this->unknownFormat->parse($number);
142 1
            } catch (InvalidAccountNumberException $exception) {
143
                // ignore failure to parse unknown account
144
            }
145
        }
146
147 1
        throw new UnableToCreateAccountException("Unable to parse account $number.");
148
    }
149
150
    /**
151
     * @param  string $number
152
     * @return array
153
     */
154 9
    private function createParseMap($number)
155
    {
156
        $parseMap = [
157 9
            'success' => [],
158
            'rewrite' => []
159
        ];
160
161 9
        $rewrites = array_map(
162 9
            function (RewriterStrategy $strategy) use ($number) {
163 9
                return $strategy->rewrite($number);
164 9
            },
165 9
            $this->rewriteStrategies
166
        );
167
168 9
        foreach ($this->formats as $format) {
169
            try {
170 9
                $parseMap['success'][] = $format->parse($number);
171 7
            } catch (InvalidAccountNumberException $exception) {
172 7
                foreach ($rewrites as $rewrite) {
173
                    try {
174 7
                        $parseMap['rewrite'][] = $format->parse($rewrite);
175 4
                    } catch (InvalidAccountNumberException $e) {
176 9
                        continue;
177
                    }
178
                }
179
            }
180
        }
181
182 9
        return $parseMap;
183
    }
184
}
185