• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

nepada / presenter-mapping / 6342715702

28 Sep 2023 06:12PM UTC coverage: 91.667%. Remained the same
6342715702

push

github

xificurk
Drop useless dev dependency

77 of 84 relevant lines covered (91.67%)

0.92 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

92.59
/src/PresenterMapping/PresenterMapper.php
1
<?php
2
declare(strict_types = 1);
3

4
namespace Nepada\PresenterMapping;
5

6
use Nette;
7
use Nette\Utils\Strings;
8

9
class PresenterMapper
10
{
11

12
    use Nette\SmartObject;
13

14
    /**
15
     * @var string[] of presenter name => class
16
     */
17
    private array $presenterMapping = [];
18

19
    /**
20
     * @var string[][] of module => splitted mask
21
     */
22
    private array $moduleMapping = [
23
        '' => ['', '*Module\\', '*Presenter'],
24
        'Nette' => ['NetteModule\\', '*\\', '*Presenter'],
25
    ];
26

27
    /**
28
     * Sets mapping as pairs [module:* => mask, presenter => class]:
29
     * Example 1 - set class of specific presenter:
30
     *      ['Bar' => 'App\BarPresenter', 'Module:SubModule:Presenter' => 'Namespace\Whatever\PresenterClass']
31
     * Example 2 - set mapping for modules:
32
     *      ['App:Foo' => 'App\FooModule\*Module\*Presenter', '*' => '*Module\*Presenter']
33
     *
34
     * @param string[]|string[][] $mapping
35
     * @return $this
36
     */
37
    public function setMapping(array $mapping): static
1✔
38
    {
39
        foreach ($mapping as $name => $mask) {
1✔
40
            if (is_string($mask) && strpos($mask, '*') === false) {
1✔
41
                $this->setPresenterMapping($name, $mask);
1✔
42
            } else {
43
                $this->setModuleMapping(rtrim($name, '*'), $mask);
1✔
44
            }
45
        }
46
        return $this;
1✔
47
    }
48

49
    public function setPresenterMapping(string $presenter, string $class): static
1✔
50
    {
51
        $presenter = trim($presenter, ':');
1✔
52
        $class = ltrim($class, '\\');
1✔
53

54
        $conflict = array_search($class, $this->presenterMapping, true);
1✔
55
        if ($conflict !== false) {
1✔
56
            throw new \InvalidArgumentException("Presenter class conflict: '$conflict' and '$presenter' both point to '$class'.");
×
57
        }
58

59
        $this->presenterMapping[$presenter] = $class;
1✔
60
        return $this;
1✔
61
    }
62

63
    /**
64
     * @param string|string[] $mask
65
     * @return $this
66
     */
67
    public function setModuleMapping(string $module, string|array $mask): static
1✔
68
    {
69
        $module = trim($module, ':');
1✔
70
        if (is_array($mask) && count($mask) === 3) {
1✔
71
            $this->moduleMapping[$module] = [$mask[0] !== '' ? $mask[0] . '\\' : '', $mask[1] . '\\', $mask[2]];
1✔
72
        } elseif (is_string($mask)) {
1✔
73
            $m = Strings::match($mask, '#^\\\\?([\w\\\\]*\\\\)?(\w*\*\w*?\\\\)?([\w\\\\]*\*\w*)\z#');
1✔
74
            if ($m === null) {
1✔
75
                $module = $module === '' ? '*' : $module;
×
76
                throw new \InvalidArgumentException("Invalid mapping mask '$mask' for module '$module'.");
×
77
            }
78
            $this->moduleMapping[$module] = [$m[1], $m[2] !== '' ? $m[2] : '*Module\\', $m[3]];
1✔
79
        } else {
80
            $module = $module === '' ? '*' : $module;
1✔
81
            throw new \InvalidArgumentException("Invalid mapping mask for module '$module'.");
1✔
82
        }
83
        uksort(
1✔
84
            $this->moduleMapping,
1✔
85
            fn (string $a, string $b): int => [substr_count($b, ':'), $b] <=> [substr_count($a, ':'), $a],
1✔
86
        );
87
        return $this;
1✔
88
    }
89

90
    /**
91
     * Formats presenter class name from its name.
92
     */
93
    public function formatPresenterClass(string $presenter): string
1✔
94
    {
95
        if (isset($this->presenterMapping[$presenter])) {
1✔
96
            return $this->presenterMapping[$presenter];
1✔
97
        }
98

99
        $parts = explode(':', $presenter);
1✔
100
        $presenterName = array_pop($parts);
1✔
101
        $modules = [];
1✔
102
        while (! isset($this->moduleMapping[implode(':', $parts)])) {
1✔
103
            array_unshift($modules, (string) array_pop($parts));
1✔
104
        }
105
        $mapping = $this->moduleMapping[implode(':', $parts)];
1✔
106

107
        $class = $mapping[0];
1✔
108
        foreach ($modules as $module) {
1✔
109
            $class .= str_replace('*', $module, $mapping[1]);
1✔
110
        }
111
        $class .= str_replace('*', $presenterName, $mapping[2]);
1✔
112

113
        return $class;
1✔
114
    }
115

116
    /**
117
     * Formats presenter name from class name.
118
     */
119
    public function unformatPresenterClass(string $class): ?string
1✔
120
    {
121
        $presenter = array_search($class, $this->presenterMapping, true);
1✔
122
        if ($presenter !== false) {
1✔
123
            return (string) $presenter;
1✔
124
        }
125

126
        foreach ($this->moduleMapping as $module => $mapping) {
1✔
127
            $mapping = str_replace(['\\', '*'], ['\\\\', '(\w+)'], $mapping);
1✔
128
            $matches = Strings::match($class, "#^\\\\?$mapping[0]((?:$mapping[1])*)$mapping[2]\\z#i");
1✔
129
            if ($matches !== null) {
1✔
130
                return ($module === '' ? '' : $module . ':') . Strings::replace($matches[1], "#$mapping[1]#iA", '$1:') . $matches[3];
1✔
131
            }
132
        }
133

134
        return null;
×
135
    }
136

137
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc