1: <?php
2:
3: 4: 5: 6:
7:
8: namespace Nette\Application;
9:
10: use Nette;
11:
12:
13: 14: 15: 16: 17:
18: class PresenterFactory extends Nette\Object implements IPresenterFactory
19: {
20:
21: public $caseSensitive = FALSE;
22:
23:
24: private $mapping = array(
25: '*' => array('', '*Module\\', '*Presenter'),
26: 'Nette' => array('NetteModule\\', '*\\', '*Presenter'),
27: );
28:
29:
30: private $baseDir;
31:
32:
33: private $cache = array();
34:
35:
36: private $container;
37:
38:
39: 40: 41:
42: public function __construct($baseDir, Nette\DI\Container $container)
43: {
44: $this->baseDir = $baseDir;
45: $this->container = $container;
46: }
47:
48:
49: 50: 51: 52: 53:
54: public function createPresenter($name)
55: {
56: $class = $this->getPresenterClass($name);
57: if (count($services = $this->container->findByType($class)) === 1) {
58: $presenter = $this->container->createService($services[0]);
59: } else {
60: $presenter = $this->container->createInstance($class);
61: }
62: $this->container->callInjects($presenter);
63:
64: if ($presenter instanceof UI\Presenter && $presenter->invalidLinkMode === NULL) {
65: $presenter->invalidLinkMode = $this->container->parameters['debugMode'] ? UI\Presenter::INVALID_LINK_WARNING : UI\Presenter::INVALID_LINK_SILENT;
66: }
67: return $presenter;
68: }
69:
70:
71: 72: 73: 74: 75: 76:
77: public function getPresenterClass(& $name)
78: {
79: if (isset($this->cache[$name])) {
80: list($class, $name) = $this->cache[$name];
81: return $class;
82: }
83:
84: if (!is_string($name) || !Nette\Utils\Strings::match($name, '#^[a-zA-Z\x7f-\xff][a-zA-Z0-9\x7f-\xff:]*\z#')) {
85: throw new InvalidPresenterException("Presenter name must be alphanumeric string, '$name' is invalid.");
86: }
87:
88: $class = $this->formatPresenterClass($name);
89:
90: if (!class_exists($class)) {
91:
92: $file = $this->formatPresenterFile($name);
93: if (is_file($file) && is_readable($file)) {
94: call_user_func(function () use ($file) { require $file; });
95: }
96:
97: if (!class_exists($class)) {
98: throw new InvalidPresenterException("Cannot load presenter '$name', class '$class' was not found in '$file'.");
99: }
100: }
101:
102: $reflection = new Nette\Reflection\ClassType($class);
103: $class = $reflection->getName();
104:
105: if (!$reflection->implementsInterface('Nette\Application\IPresenter')) {
106: throw new InvalidPresenterException("Cannot load presenter '$name', class '$class' is not Nette\\Application\\IPresenter implementor.");
107: }
108:
109: if ($reflection->isAbstract()) {
110: throw new InvalidPresenterException("Cannot load presenter '$name', class '$class' is abstract.");
111: }
112:
113:
114: $realName = $this->unformatPresenterClass($class);
115: if ($name !== $realName) {
116: if ($this->caseSensitive) {
117: throw new InvalidPresenterException("Cannot load presenter '$name', case mismatch. Real name is '$realName'.");
118: } else {
119: $this->cache[$name] = array($class, $realName);
120: $name = $realName;
121: }
122: } else {
123: $this->cache[$name] = array($class, $realName);
124: }
125:
126: return $class;
127: }
128:
129:
130: 131: 132: 133:
134: public function setMapping(array $mapping)
135: {
136: foreach ($mapping as $module => $mask) {
137: if (!preg_match('#^\\\\?([\w\\\\]*\\\\)?(\w*\*\w*?\\\\)?([\w\\\\]*\*\w*)\z#', $mask, $m)) {
138: throw new Nette\InvalidStateException("Invalid mapping mask '$mask'.");
139: }
140: $this->mapping[$module] = array($m[1], $m[2] ?: '*Module\\', $m[3]);
141: }
142: return $this;
143: }
144:
145:
146: 147: 148: 149: 150: 151:
152: public function formatPresenterClass($presenter)
153: {
154: $parts = explode(':', $presenter);
155: $mapping = isset($parts[1], $this->mapping[$parts[0]])
156: ? $this->mapping[array_shift($parts)]
157: : $this->mapping['*'];
158:
159: while ($part = array_shift($parts)) {
160: $mapping[0] .= str_replace('*', $part, $mapping[$parts ? 1 : 2]);
161: }
162: return $mapping[0];
163: }
164:
165:
166: 167: 168: 169: 170: 171:
172: public function unformatPresenterClass($class)
173: {
174: foreach ($this->mapping as $module => $mapping) {
175: $mapping = str_replace(array('\\', '*'), array('\\\\', '(\w+)'), $mapping);
176: if (preg_match("#^\\\\?$mapping[0]((?:$mapping[1])*)$mapping[2]\\z#i", $class, $matches)) {
177: return ($module === '*' ? '' : $module . ':')
178: . preg_replace("#$mapping[1]#iA", '$1:', $matches[1]) . $matches[3];
179: }
180: }
181: }
182:
183:
184: 185: 186: 187: 188:
189: public function formatPresenterFile($presenter)
190: {
191: $path = '/' . str_replace(':', 'Module/', $presenter);
192: return $this->baseDir . substr_replace($path, '/presenters', strrpos($path, '/'), 0) . 'Presenter.php';
193: }
194:
195: }
196: