В приложении одна точка входа - index.php
При этом нужно три (пока три UrlManager): UrlManagerFrontend, UrlManagerBackend, UrlManagerApi
Которые соответсвуют префиксам в роутах '' (без префикса), 'backend' и 'api' соответственно.
Т.е., например роуты:
Код: Выделить всё
'site/main/index' - UrlManagerFrontend
Код: Выделить всё
'backend/site/main/index' - UrlManagerBackend
Код: Выделить всё
'api/site/main/index' - UrlManagerFrontend
Код: Выделить всё
Yii::$app->urlManager->getManager('backend')->createUrl('site/main/index'); // backend/site/main/index
Yii::$app->urlManager->getManager('api')->createUrl('site/main/index'); // api/site/main/index
Yii::$app->urlManager->getManager('frontend')->createUrl('site/main/index'); // site/main/index
А вызов Yii::$app->urlManager->createUrl('site/main/index') будет использовать актуальный UrlManager в зависимости от префикса (или его отсутствия).
Собственно, на коленях быстро накидал вот такую реализацию:
Абстрактный класс, от которого наследуются UrlManagerFrontend, UrlManagerBackend, UrlManagerApi
Код: Выделить всё
abstract class BaseUrlManager extends \yii\web\UrlManager
{
/**
* @var \yii\web\UrlManager[]
*/
public $managers = [];
public $prefix;
/**
* @param string $name
* @return BaseUrlManager|\yii\web\UrlManager
*/
public function getManager($name)
{
if (!isset($this->managers[$name])) {
throw new InvalidParamException(Yii::t('app', '"{name}" url manager is absent.', ['name' => $name]));
}
if (is_object($this->managers[$name])) {
$manager = $this->managers[$name];
} else if ($this->managers[$name]['class'] == get_called_class()) {
$manager = $this;
} else {
$manager = Yii::createObject($this->managers[$name]);
$this->managers[$name] = $manager;
}
return $manager;
}
/**
* @inheritdoc
*/
public function createUrl($params)
{
if ($this->prefix) {
$route = trim($params[0], '/');
$route = sprintf('%s/%s', $this->prefix, $route);
$params[0] = $route;
}
return parent::createUrl($params);
}
}
Код: Выделить всё
class UrlManager extends \yii\web\UrlManager
{
public $managers = [];
protected $managersDefaults = [
'frontend' => [
'class' => 'app\extensions\web\urlManager\UrlManagerFrontend',
'prefix' => '',
],
'backend' => [
'class' => 'app\extensions\web\urlManager\UrlManagerBackend',
'prefix' => 'backend',
],
'api' => [
'class' => 'app\extensions\web\urlManager\UrlManagerApi',
'prefix' => 'api',
],
];
/**
* @inheritdoc
*/
public function __construct(array $config = [])
{
if (isset($config['managers'])) {
$this->managers = $config['managers'];
unset($config['managers']);
}
$this->configureManagers($config);
parent::__construct($config);
}
/**
* @inheritdoc
*/
public function parseRequest($request)
{
$result = parent::parseRequest($request);
list($route, $params) = $result;
$config = $this->managers['frontend'];
foreach ($this->managers as $name => $manager) {
$prefix = $manager['prefix'];
if ($prefix) {
$matched = (strpos($route, $prefix) === 0);
if ($matched) {
$config = $this->managers[$name];
$route = str_replace($name, '', $route);
$route = trim($route, '/');
$result = [$route, $params];
}
}
}
$config['managers'] = $this->managers;
\Yii::$app->set('urlManager', $config);
return $result;
}
/**
* @param array $config
*/
private function configureManagers($config)
{
$this->managers = ArrayHelper::merge($this->managersDefaults, $this->managers);
foreach ($this->managers as $name => $managerConfig) {
$this->managers[$name] = ArrayHelper::merge($config, $managerConfig);
$this->managers[$name]['rules'] = $this->managers[$name]['rules'] ?? [];
$this->managers[$name]['rules'] = array_filter($this->managers[$name]['rules'], function ($value) {
return !empty($value);
});
// if ($name == ApplicationHelper::APP_TYPE_FRONTEND) {
// $this->managers[$name]['prefix'] = '';
// } else {
// $this->managers[$name]['prefix'] = $name;
// }
}
}
}
На оформление кода внимание не обращайте, мне главное - нужно было проверить работоспособность идеи.
Такая реализация работает.
Но меня тревожит, на сколько она корректна, не не вылезут ли в процессе работы какие-то косяки?