Completed
Pull Request — master (#13)
by
unknown
05:32
created

AccountFactory::createAccount()   F

Complexity

Conditions 18
Paths 416

Size

Total Lines 109
Code Lines 64

Duplication

Lines 34
Ratio 31.19 %

Code Coverage

Tests 53
CRAP Score 18

Importance

Changes 0
Metric Value
dl 34
loc 109
ccs 53
cts 53
cp 1
rs 3.5909
c 0
b 0
f 0
cc 18
eloc 64
nc 416
nop 1
crap 18

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 110
     * @param RewriterStrategy[] $preprocessors Preprocessors used to alter account before parsing starts
49
     */
50
    public function __construct(
51
        array $formats = [],
52
        array $rewrites = null,
53
        $allowRewrites = true,
54
        $allowUnknown = true,
55 110
        $preprocessors = null
56 110
    ) {
57 110
        $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 110
        $this->rewrites = is_array($rewrites) ? $rewrites : (new RewriterFactory)->createRewrites();
59 110
        $this->allowRewrites = $allowRewrites;
60 110
        $this->unknownFormat = $allowUnknown ? new UnknownFormat : null;
61
        $this->preprocessors = is_array($preprocessors) ? $preprocessors : (new RewriterFactory)->createPreprocessors();
62
    }
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 1
     * @return null
72
     */
73 1
    public function whitelistFormats(array $formats)
74 1
    {
75 1
        foreach ($this->formats as $formatId => $format) {
76
            if (!in_array($formatId, $formats)) {
77
                unset($this->formats[$formatId]);
78 1
            }
79
        }
80
    }
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 100
     * @return null
90
     */
91 100
    public function blacklistFormats(array $formats)
92 18
    {
93
        foreach ($formats as $format) {
94 100
            unset($this->formats[$format]);
95
        }
96
    }
97
98
    /**
99
     * Create bank account object using number
100
     *
101
     * @param  string $number
102
     * @return AccountNumber
103 110
     * @throws UnableToCreateAccountException If unable to create
104
     */
105 110
    public function createAccount($number)
106 105
    {
107
        foreach ($this->preprocessors as $preprocessor) {
108
            $number = $preprocessor->rewrite($number);
109
        }
110 110
111
        $parseMap = [
112
            'success' => [],
113
            'rewrite' => [],
114
            'exception' => []
115 110
        ];
116
117 104
        $rewrites = array_map(
118 110
            function (RewriterStrategy $strategy) use ($number) {
119 110
                return $strategy->rewrite($number);
120
            },
121
            $this->rewrites
122 110
        );
123
124 110
        foreach ($this->formats as $format) {
125 101
            try {
126 106
                $parseMap['success'][] = $format->parse($number);
127 106
                continue;
128 2
            } catch (InvalidAccountNumberException $exception) {
129
                if ($exception instanceof InvalidCheckDigitException) {
130
                    $parseMap['exception'] = $exception;
131 106
                }
132
133 103
                if(!($exception instanceof InvalidClearingNumberException)) {
134 100
                   $clearing_validator = $format->get_validator(ClearingValidator::class);
135 106
                   if($clearing_validator) {
136
                      if($clearing_validator->validateClearingNumber($number)) {
0 ignored issues
show
Bug introduced by
The method validateClearingNumber() does not exist on byrokrat\banking\Validator. Did you maybe mean validate()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
137
                         $parseMap['exception'] = $exception;
138
                      }
139
                   }
140
                }
141 110
142 100
                foreach ($rewrites as $rewrite) {
143
                    try {
144
                        $parseMap['rewrite'][] = $format->parse($rewrite);
145 11
                    } catch (InvalidAccountNumberException $e) {
146 1
                        continue;
147 1
                    }
148 1
                }
149 1
            }
150 1
        }
151 1
152 1
        if (count($parseMap['success']) == 1) {
153
            return $parseMap['success'][0];
154 1
        }
155 1
156 1 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...
157
            throw new UnableToCreateAccountException(
158
                sprintf(
159
                    'Unable to parse account %s, multiple matching formats: %s.',
160
                    $number,
161
                    implode(
162
                        ' and ',
163 10
                        array_map(
164 2
                            function (AccountNumber $account) {
165
                                return $account->getBankName();
166
                            },
167 8
                            $parseMap['success']
168 2
                        )
169 2
                    )
170 2
                )
171 2
            );
172 2
        }
173 2
174 2
        if (count($parseMap['rewrite']) == 1 && $this->allowRewrites) {
175 2
            return $parseMap['rewrite'][0];
176 2
        }
177 2
178 2 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...
179
            throw new UnableToCreateAccountException(
180
                sprintf(
181
                    'Unable to parse account %s. You may rewrite number as: %s.',
182
                    $number,
183
                    implode(
184
                        ' or ',
185 6
                        array_map(
186 1
                            function (AccountNumber $account) {
187 1
                                return $account->getNumber();
188 1
                            },
189 1
                            $parseMap['rewrite']
190
                        )
191
                    )
192
                )
193 5
            );
194
        }
195 5
196 1
        if ($parseMap['exception']) {
197
            throw new UnableToCreateAccountException(
198
                "Unable to parse account $number: {$parseMap['exception']->getMessage()}",
199
                0,
200
                $parseMap['exception']
201 1
            );
202
        }
203
204
        if ($this->unknownFormat) {
205
            try {
206
                return $this->unknownFormat->parse($number);
207
            } catch (InvalidAccountNumberException $exception) {
208
                // ignore failure to parse unknown account
209
            }
210
        }
211
212
        throw new UnableToCreateAccountException("Unable to parse account $number.");
213
    }
214
}
215