Passed
Push — master ( 265c0b...e337ae )
by Webnet
01:48
created

ConfigGuesser::toSnakeCase()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 5
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace WebnetFr\DatabaseAnonymizer\ConfigGuesser;
4
5
use Doctrine\DBAL\Connection;
6
use WebnetFr\DatabaseAnonymizer\Exception\GuesserMissingHintException;
7
8
/**
9
 * @author Vlad Riabchenko <[email protected]>
10
 */
11
class ConfigGuesser
12
{
13
    /**
14
     * @var ConfigGuesserHint[]
15
     */
16
    private static $hints;
17
18
    public function __construct()
19
    {
20
        self::$hints = [
21
            (new ConfigGuesserHint('firstName'))->words([['first', 'name'], 'prenom'])->arguments([null]),
22
            (new ConfigGuesserHint('firstName'))->words(['prenom'])->locale('fr_FR')->arguments([null]),
23
            (new ConfigGuesserHint('lastName'))->words([['last', 'name']]),
24
            (new ConfigGuesserHint('lastName'))->words(['nom'])->locale('fr_FR'),
25
            (new ConfigGuesserHint('city'))->words(['city', 'town', 'ville']),
26
            (new ConfigGuesserHint('streetAddress'))->words(['address', 'adresse']),
27
            (new ConfigGuesserHint('postcode'))->words([['post', 'code'], 'zip']),
28
            (new ConfigGuesserHint('postcode'))->words([['code', 'postal'], 'cp'])->locale('fr_FR'),
29
            (new ConfigGuesserHint('country'))->words(['country', 'pays']),
30
            (new ConfigGuesserHint('phoneNumber'))->words(['phone']),
31
            (new ConfigGuesserHint('realText'))->words(['comment'])->arguments([200, 2]),
32
            (new ConfigGuesserHint('realText'))->words(['commentaire'])->arguments([200, 2])->locale('fr_FR'),
33
            (new ConfigGuesserHint('dateTimeBetween'))->words(['birthdate', 'birthday'])->arguments(['-30 years', 'now', null])->date(true),
34
            (new ConfigGuesserHint('safeEmail'))->words(['email', 'mail']),
35
            (new ConfigGuesserHint('userName'))->words(['username'])->unique(true),
36
            (new ConfigGuesserHint('password'))->words(['password']),
37
            (new ConfigGuesserHint('creditCardNumber'))->words([['credit', 'card'], ['credit', 'carte'], 'cb']),
38
            (new ConfigGuesserHint('siren'))->words(['siren'])->locale('fr_FR')->unique(true),
39
            (new ConfigGuesserHint('siret'))->words(['siret'])->locale('fr_FR')->unique(true),
40
            (new ConfigGuesserHint('vat'))->words(['vat'])->locale('fr_FR')->unique(true),
41
            (new ConfigGuesserHint('nir'))->words(['nir', ['securite', 'sociale']])->locale('fr_FR')->unique(true),
42
        ];
43
    }
44
45
    /**
46
     * @param Connection $connection
47
     *
48
     * @return array
49
     */
50
    public static function guess(Connection $connection)
51
    {
52
        $hints = [];
53
        $sm = $connection->getSchemaManager();
54
55
        foreach ($sm->listTables() as $table) {
56
            $tableName = $table->getName();
57
58
            foreach ($table->getColumns() as $column) {
59
                $columnName = $column->getName();
60
61
                try {
62
                    $hints[$tableName][$columnName] = self::guessColumn($columnName);
63
                } catch (GuesserMissingHintException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
64
                }
65
            }
66
        }
67
68
        return $hints;
69
    }
70
71
    /**
72
     * @param string $name
73
     *
74
     * @throws GuesserMissingHintException
75
     *
76
     * @return ConfigGuesserHint
77
     */
78
    private static function guessColumn(string $name)
79
    {
80
        $columnWords = self::toWords($name);
81
82
        foreach (self::$hints as $hint) {
83
            foreach ($hint->words as $word) {
84
                if (\is_string($word) && \in_array($word, $columnWords, true)) {
85
                    return $hint;
86
                }
87
88
                if (\is_array($word) && \count(array_intersect($word, $columnWords)) == \count($word)) {
89
                    return $hint;
90
                }
91
            }
92
        }
93
94
        throw new GuesserMissingHintException();
95
    }
96
97
    /**
98
     * @param string $str
99
     *
100
     * @return array
101
     *
102
     * @author Vlad Riabchenko <[email protected]>
103
     */
104
    private static function toWords(string $str)
105
    {
106
        $snake = self::toSnakeCase(preg_replace('/\d/', '', $str));
107
108
        return explode('_', $snake);
109
    }
110
111
    /**
112
     * @param string $str
113
     *
114
     * @return string
115
     */
116
    private static function toSnakeCase(string $str)
117
    {
118
        $pieces = preg_split('/((?<=.)(?=[[:upper:]][[:lower:]])|(?<=[[:lower:]])(?=[[:upper:]]))/', $str);
119
120
        return strtolower(implode('_', $pieces));
0 ignored issues
show
Bug introduced by
It seems like $pieces can also be of type false; however, parameter $pieces of implode() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

120
        return strtolower(implode('_', /** @scrutinizer ignore-type */ $pieces));
Loading history...
121
    }
122
}
123