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

nette / application / 27919019709

21 Jun 2026 10:08PM UTC coverage: 84.111% (+0.05%) from 84.059%
27919019709

push

github

dg
phpstan fix

2038 of 2423 relevant lines covered (84.11%)

0.84 hits per line

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

86.36
/src/Application/PresenterFactory.php
1
<?php declare(strict_types=1);
2

3
/**
4
 * This file is part of the Nette Framework (https://nette.org)
5
 * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
6
 */
7

8
namespace Nette\Application;
9

10
use Nette;
11
use function array_shift, class_exists, count, explode, is_array, is_string, is_subclass_of, preg_match, strtr;
12

13

14
/**
15
 * Default presenter loader.
16
 */
17
class PresenterFactory implements IPresenterFactory
18
{
19
        /** @var array<string, array{string, string, string}>  module => splited mask */
20
        private array $mapping = [
21
                '*' => ['', '*Module\\', '*Presenter'],
22
                'Nette' => ['NetteModule\\', '*\\', '*Presenter'],
23
        ];
24

25
        /** @var array<string, string> */
26
        private array $aliases = [];
27

28
        /** @var array<string, class-string<IPresenter>> */
29
        private array $cache = [];
30

31
        /** @var \Closure(class-string<IPresenter>): IPresenter */
32
        private \Closure $factory;
33

34

35
        /**
36
         * @param  ?callable(class-string<IPresenter>): IPresenter  $factory
37
         */
38
        public function __construct(?callable $factory = null)
1✔
39
        {
40
                $this->factory = $factory
1✔
41
                        ? $factory(...)
1✔
42
                        : fn(string $class): IPresenter => new $class;
1✔
43
        }
1✔
44

45

46
        /**
47
         * Creates new presenter instance.
48
         */
49
        public function createPresenter(string $name): IPresenter
50
        {
51
                return ($this->factory)($this->getPresenterClass($name));
×
52
        }
53

54

55
        /**
56
         * Generates and checks presenter class name.
57
         * @return class-string<IPresenter>
58
         * @throws InvalidPresenterException
59
         */
60
        public function getPresenterClass(string &$name): string
1✔
61
        {
62
                if (isset($this->cache[$name])) {
1✔
63
                        return $this->cache[$name];
1✔
64
                }
65

66
                $class = $this->formatPresenterClass($name);
1✔
67
                if (!class_exists($class)) {
1✔
68
                        throw new InvalidPresenterException("Cannot load presenter '$name', class '$class' was not found.");
×
69
                }
70

71
                $reflection = new \ReflectionClass($class);
1✔
72
                $class = $reflection->getName();
1✔
73
                if (!is_subclass_of($class, IPresenter::class)) {
1✔
74
                        throw new InvalidPresenterException("Cannot load presenter '$name', class '$class' is not Nette\\Application\\IPresenter implementor.");
×
75
                } elseif ($reflection->isAbstract()) {
1✔
76
                        throw new InvalidPresenterException("Cannot load presenter '$name', class '$class' is abstract.");
×
77
                }
78

79
                return $this->cache[$name] = $class;
1✔
80
        }
81

82

83
        /**
84
         * Sets mapping as pairs [module => mask]
85
         * @param array<string, string|array{string, string, string}>  $mapping
86
         */
87
        public function setMapping(array $mapping): static
1✔
88
        {
89
                foreach ($mapping as $module => $mask) {
1✔
90
                        if (is_string($mask)) {
1✔
91
                                if (!preg_match('#^\\\?([\w\\\]*\\\)?(\w*\*\w*?\\\)?([\w\\\]*\*\*?\w*)$#D', $mask, $m)) {
1✔
92
                                        throw new Nette\InvalidStateException("Invalid mapping mask '$mask'.");
×
93
                                }
94

95
                                $this->mapping[$module] = [$m[1], $m[2] ?: '*Module\\', $m[3]];
1✔
96
                        } elseif (is_array($mask) && count($mask) === 3) {
1✔
97
                                $this->mapping[$module] = [$mask[0] ? $mask[0] . '\\' : '', $mask[1] . '\\', $mask[2]];
1✔
98
                        } else {
99
                                throw new Nette\InvalidStateException("Invalid mapping mask for module $module.");
1✔
100
                        }
101
                }
102

103
                return $this;
1✔
104
        }
105

106

107
        /**
108
         * Formats presenter class name from its name.
109
         * @internal
110
         */
111
        public function formatPresenterClass(string $presenter): string
1✔
112
        {
113
                if (!Nette\Utils\Strings::match($presenter, '#^[a-zA-Z\x7f-\xff][a-zA-Z0-9\x7f-\xff:]*$#D')) {
1✔
114
                        throw new InvalidPresenterException("Presenter name must be alphanumeric string, '$presenter' is invalid.");
×
115
                }
116
                $parts = explode(':', $presenter);
1✔
117
                $mapping = isset($parts[1], $this->mapping[$parts[0]])
1✔
118
                        ? $this->mapping[array_shift($parts)]
1✔
119
                        : $this->mapping['*'];
1✔
120

121
                while ($part = array_shift($parts)) {
1✔
122
                        $mapping[0] .= strtr($mapping[$parts ? 1 : 2], ['**' => "$part\\$part", '*' => $part]);
1✔
123
                }
124

125
                return $mapping[0];
1✔
126
        }
127

128

129
        /**
130
         * Sets pairs [alias => destination]
131
         * @param array<string, string>  $aliases
132
         */
133
        public function setAliases(array $aliases): static
1✔
134
        {
135
                $this->aliases = $aliases;
1✔
136
                return $this;
1✔
137
        }
138

139

140
        /**
141
         * Returns the destination registered under the given alias, or throws if not found.
142
         */
143
        public function getAlias(string $alias): string
1✔
144
        {
145
                return $this->aliases[$alias] ?? throw new Nette\InvalidStateException("Link alias '$alias' was not found.");
1✔
146
        }
147
}
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