PublicReferenceGeneratorImpl::create()   A
last analyzed

Complexity

Conditions 4
Paths 4

Size

Total Lines 25

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 0
Metric Value
dl 0
loc 25
ccs 0
cts 18
cp 0
rs 9.52
c 0
b 0
f 0
cc 4
nc 4
nop 1
crap 20
1
<?php
2
/**
3
 * Created by IntelliJ IDEA.
4
 * User: gerk
5
 * Date: 14.04.17
6
 * Time: 22:40
7
 */
8
9
namespace PeekAndPoke\Component\Slumber\Data\Addon\PublicReference;
10
11
use PeekAndPoke\Component\Slumber\Data\Error\DuplicateError;
12
use PeekAndPoke\Component\Slumber\Data\Repository;
13
14
/**
15
 * @author Karsten J. Gerber <[email protected]>
16
 */
17
class PublicReferenceGeneratorImpl implements PublicReferenceGenerator
18
{
19
    public static $REDUCED_UPPER_CHARS = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'K', 'L', 'M', 'N', 'P', 'R', 'S', 'T', 'V', 'W', 'X', 'Y', 'Z'];
20
21
    /** @var Repository */
22
    private $repository;
23
    /** @var string */
24
    private $pattern;
25
    /** @var array */
26
    private $cls2pattern;
27
28
    /**
29
     * PublicReferenceGeneratorImpl constructor.
30
     *
31
     * @param Repository $repository
32
     * @param string     $pattern
33
     * @param array      $cls2pattern
34
     */
35
    public function __construct(Repository $repository, $pattern = '$$-__-########', array $cls2pattern = [])
36
    {
37
        $this->repository  = $repository;
38
        $this->pattern     = $pattern;
39
        $this->cls2pattern = $cls2pattern;
40
    }
41
42
    /**
43
     * @param mixed $subject The object to create a public unique reference for
44
     *
45
     * @return null|string
46
     */
47
    public function create($subject)
48
    {
49
        if (! \is_object($subject)) {
50
            return null;
51
        }
52
53
        $reflect = new \ReflectionClass($subject);
54
        $pattern = $this->cls2pattern[$reflect->name] ?? $this->pattern;
55
        $tries   = 1000;
56
57
        while (--$tries >= 0) {
58
59
            $new = $this->generate($pattern, $reflect->getShortName());
60
61
            try {
62
                $this->repository->insert((new PublicReference())->setId($new));
63
64
                return $new;
65
66
            } catch (DuplicateError $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
67
            }
68
        }
69
70
        throw new \RuntimeException('Could not generate a unique public reference');
71
    }
72
73
74
    /**
75
     * @param string $pattern
76
     * @param string $className
77
     *
78
     * @return string
79
     */
80
    private function generate($pattern, $className)
81
    {
82
        $ret           = '';
83
        $classNameIdx  = 0;
84
        $patternLength = \strlen($pattern);
85
86
        for ($i = 0; $i < $patternLength; $i++) {
87
88
            $char = $pattern[$i];
89
90
            switch ($char) {
91
                case '_':
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
92
                    $ret .= self::$REDUCED_UPPER_CHARS[random_int(0, \count(static::$REDUCED_UPPER_CHARS) - 1)];
93
                    break;
94
95
                case '#':
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
96
                    $ret .= random_int(0, 9);
97
                    break;
98
99
                case '$':
100
                    $ret .= strtoupper($className[$classNameIdx++]);
101
                    break;
102
103
                default:
104
                    $ret .= $char;
105
                    break;
106
            }
107
        }
108
109
        return $ret;
110
    }
111
}
112