Skip to content

Instantly share code, notes, and snippets.

@xificurk
Created March 15, 2016 19:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save xificurk/3eb69d7f3f7dd44abbcd to your computer and use it in GitHub Desktop.
Save xificurk/3eb69d7f3f7dd44abbcd to your computer and use it in GitHub Desktop.
<?php
class PresenterMapper extends Nette\Object
{
/** @var array of presenter name => class */
private $presenterMapping = [];
/** @var array[] of module => splitted mask */
private $moduleMapping = [
'' => ['', '*Module\\', '*Presenter'],
'Nette' => ['NetteModule\\', '*\\', '*Presenter'],
];
/**
* Sets mapping as pairs [module:* => mask, presenter => class]:
* Example 1 - set class of specific presenter:
* ['Bar' => 'App\BarPresenter', 'Module:SubModule:Presenter' => 'Namespace\Whatever\PresenterClass']
* Example 2 - set mapping for modules:
* ['App:Foo' => 'App\FooModule\*Module\*Presenter', '*' => '*Module\*Presenter']
*
* @param array $mapping
* @return self
* @throws Nette\InvalidStateException
*/
public function setMapping(array $mapping)
{
foreach ($mapping as $name => $mask) {
if (strpos($mask, '*') === false) {
$this->setPresenterMapping($name, $mask);
} else {
$this->setModuleMapping(rtrim($name, '*'), $mask);
}
}
return $this;
}
/**
* @param string $presenter
* @param string $class
* @return self
* @throws Nette\InvalidStateException
*/
public function setPresenterMapping($presenter, $class)
{
$presenter = trim($presenter, ':');
$class = ltrim($class, '\\');
if ($conflict = array_search($class, $this->presenterMapping, true)) {
throw new Nette\InvalidStateException("Presenter class conflict: '$conflict' and '$presenter' both point to '$class'.");
}
$this->presenterMapping[$presenter] = $class;
return $this;
}
/**
* @param string $module
* @param string $mask
* @return self
* @throws Nette\InvalidArgumentException
*/
public function setModuleMapping($module, $mask)
{
if (!preg_match('#^\\\\?([\w\\\\]*\\\\)?(\w*\*\w*?\\\\)?([\w\\\\]*\*\w*)\z#', $mask, $m)) {
throw new Nette\InvalidArgumentException("Invalid module mapping mask '$mask'.");
}
$this->moduleMapping[trim($module, ':')] = [$m[1], $m[2] ?: '*Module\\', $m[3]];
uksort($this->moduleMapping, function ($a, $b) {return (substr_count($b, ':') - substr_count($a, ':')) ?: strcmp($b, $a);});
return $this;
}
/**
* Formats presenter class name from its name.
*
* @param string $presenter
* @return string
*/
public function formatPresenterClass($presenter)
{
if (isset($this->presenterMapping[$presenter])) {
return $this->presenterMapping[$presenter];
}
$parts = explode(':', $presenter);
$presenterName = array_pop($parts);
$modules = [];
while (!isset($this->moduleMapping[implode(':', $parts)])) {
array_unshift($modules, array_pop($parts));
}
$mapping = $this->moduleMapping[implode(':', $parts)];
$class = $mapping[0];
foreach ($modules as $module) {
$class .= str_replace('*', $module, $mapping[1]);
}
$class .= str_replace('*', $presenterName, $mapping[2]);
return $class;
}
/**
* Formats presenter name from class name.
*
* @param string $class
* @return string
*/
public function unformatPresenterClass($class)
{
if ($presenter = array_search($class, $this->presenterMapping, true)) {
return $presenter;
}
foreach ($this->moduleMapping as $module => $mapping) {
$mapping = str_replace(['\\', '*'], ['\\\\', '(\w+)'], $mapping);
if (preg_match("#^\\\\?$mapping[0]((?:$mapping[1])*)$mapping[2]\\z#i", $class, $matches)) {
return ($module === '' ? '' : $module . ':') . preg_replace("#$mapping[1]#iA", '$1:', $matches[1]) . $matches[3];
}
}
return null;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment