Completed
Pull Request — master (#13)
by
unknown
01:38
created

AccountFactory::createAccount()   D

Complexity

Conditions 17
Paths 224

Size

Total Lines 104
Code Lines 61

Duplication

Lines 34
Ratio 32.69 %

Code Coverage

Tests 43
CRAP Score 20.6134

Importance

Changes 0
Metric Value
dl 34
loc 104
ccs 43
cts 56
cp 0.7679
rs 4.1306
c 0
b 0
f 0
cc 17
eloc 61
nc 224
nop 1
crap 20.6134

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace byrokrat\banking;
4
5
use byrokrat\banking\Exception\InvalidClearingNumberException;
6
use byrokrat\banking\Rewriter\RewriterStrategy;
7
use byrokrat\banking\Rewriter\RewriterFactory;
8
use byrokrat\banking\Exception\UnableToCreateAccountException;
9
use byrokrat\banking\Exception\InvalidAccountNumberException;
10
use byrokrat\banking\Exception\InvalidCheckDigitException;
11
use byrokrat\banking\Validator\ClearingValidator;
12
13
/**
14
 * Account number factory
15
 */
16
class AccountFactory
17
{
18
    /**
19
     * @var Format[] Possible formats used when parsing account
20
     */
21
    private $formats;
22
23
    /**
24
     * @var RewriterStrategy[] Strategies for rewriting failing account numbers
25
     */
26
    private $rewrites;
27
28
    /**
29
     * @var bool Flag if rewrites should be allowed when creating account objects
30
     */
31
    private $allowRewrites;
32
33
    /**
34
     * @var UnknownFormat The unknown format or null if unknown is disallowed
35
     */
36
    private $unknownFormat;
37
38
    /**
39
     * @var RewriterStrategy[] Preprocessors used to alter account before parsing starts
40
     */
41
    private $preprocessors;
42
43
    /**
44
     * @param Format[]           $formats       Possible formats used when parsing account
45
     * @param RewriterStrategy[] $rewrites      Rewrites used if parsed the raw account number fails
46
     * @param boolean            $allowRewrites Flag if rewrites should be allowed when creating account objects
47
     * @param boolean            $allowUnknown  Flag if the unknown account format should be used
48
     * @param RewriterStrategy[] $preprocessors Preprocessors used to alter account before parsing starts
49
     */
50 108
    public function __construct(
51
        array $formats = [],
52
        array $rewrites = null,
53
        $allowRewrites = true,
54
        $allowUnknown = true,
55
        $preprocessors = null
56
    ) {
57 108
        $this->formats = $formats ?: (new FormatFactory)->createFormats();
0 ignored issues
show
Documentation Bug introduced by
It seems like $formats ?: (new \byrokr...ory())->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...
58 108
        $this->rewrites = is_array($rewrites) ? $rewrites : (new RewriterFactory)->createRewrites();
59 108
        $this->allowRewrites = $allowRewrites;
60 108
        $this->unknownFormat = $allowUnknown ? new UnknownFormat : null;
61 108
        $this->preprocessors = is_array($preprocessors) ? $preprocessors : (new RewriterFactory)->createPreprocessors();
62 108
    }
63
64
    /**
65
     * Enable formats
66
     *
67
     * Please note that formats not listed will be dropped and
68
     * can not be recovered.
69
     *
70
     * @param  string[] $formats List of formats to whitelist
71
     * @return null
72
     */
73 1
    public function whitelistFormats(array $formats)
74
    {
75 1
        foreach ($this->formats as $formatId => $format) {
76 1
            if (!in_array($formatId, $formats)) {
77 1
                unset($this->formats[$formatId]);
78
            }
79
        }
80 1
    }
81
82
    /**
83
     * Disable formats
84
     *
85
     * Please note that listed formats will be dropped and
86
     * can not be recovered.
87
     *
88
     * @param  string[] $formats List of formats to blacklist
89
     * @return null
90
     */
91 100
    public function blacklistFormats(array $formats)
92
    {
93 100
        foreach ($formats as $format) {
94 18
            unset($this->formats[$format]);
95
        }
96 100
    }
97
98
    /**
99
     * Create bank account object using number
100
     *
101
     * @param  string $number
102
     * @return AccountNumber
103
     * @throws UnableToCreateAccountException If unable to create
104
     */
105 108
    public function createAccount($number)
106
    {
107 108
        foreach ($this->preprocessors as $preprocessor) {
108 105
            $number = $preprocessor->rewrite($number);
109
        }
110
111
        $parseMap = [
112 108
            'success' => [],
113
            'rewrite' => [],
114
            'exception' => []
115
        ];
116
117 108
        $rewrites = array_map(
118
            function (RewriterStrategy $strategy) use ($number) {
119 102
                return $strategy->rewrite($number);
120 108
            },
121 108
            $this->rewrites
122
        );
123
124 108
        foreach ($this->formats as $format) {
125
            try {
126 108
                $parseMap['success'][] = $format->parse($number);
127 101
                continue;
128 104
            } catch (InvalidAccountNumberException $exception) {
129 104
                if ($exception instanceof InvalidCheckDigitException) {
130 2
                    $parseMap['exception'] = $exception;
131
                }
132
133 104
                if($format->has_validator(ClearingValidator::class) AND !($exception instanceof InvalidClearingNumberException)) {
134 99
                    $parseMap['exception'] = $exception;
135
                }
136
137 100
                foreach ($rewrites as $rewrite) {
138
                    try {
139 100
                        $parseMap['rewrite'][] = $format->parse($rewrite);
140 100
                    } catch (InvalidAccountNumberException $e) {
141 100
                        continue;
142
                    }
143
                }
144
            }
145
        }
146
147 104
        if (count($parseMap['success']) == 1) {
148 100
            return $parseMap['success'][0];
149
        }
150
151 5 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...
152 1
            throw new UnableToCreateAccountException(
153 1
                sprintf(
154 1
                    'Unable to parse account %s, multiple matching formats: %s.',
155 1
                    $number,
156 1
                    implode(
157 1
                        ' and ',
158 1
                        array_map(
159
                            function (AccountNumber $account) {
160 1
                                return $account->getBankName();
161 1
                            },
162 1
                            $parseMap['success']
163
                        )
164
                    )
165
                )
166
            );
167
        }
168
169 4
        if (count($parseMap['rewrite']) == 1 && $this->allowRewrites) {
170 1
            return $parseMap['rewrite'][0];
171
        }
172
173 3 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...
174
            throw new UnableToCreateAccountException(
175
                sprintf(
176
                    'Unable to parse account %s. You may rewrite number as: %s.',
177
                    $number,
178
                    implode(
179
                        ' or ',
180
                        array_map(
181
                            function (AccountNumber $account) {
182
                                return $account->getNumber();
183
                            },
184
                            $parseMap['rewrite']
185
                        )
186
                    )
187
                )
188
            );
189
        }
190
191 3
        if ($parseMap['exception']) {
192 2
            throw new UnableToCreateAccountException(
193 2
                "Unable to parse account $number: {$parseMap['exception']->getMessage()}",
194 2
                0,
195 2
                $parseMap['exception']
196
            );
197
        }
198
199 1
        if ($this->unknownFormat) {
200
            try {
201 1
                return $this->unknownFormat->parse($number);
202
            } catch (InvalidAccountNumberException $exception) {
203
                // ignore failure to parse unknown account
204
            }
205
        }
206
207
        throw new UnableToCreateAccountException("Unable to parse account $number.");
208
    }
209
}
210