GroupUrlRule.php 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. <?php
  2. /**
  3. * @link http://www.yiiframework.com/
  4. * @copyright Copyright (c) 2008 Yii Software LLC
  5. * @license http://www.yiiframework.com/license/
  6. */
  7. namespace yii\web;
  8. use Yii;
  9. use yii\base\InvalidConfigException;
  10. /**
  11. * GroupUrlRule represents a collection of URL rules sharing the same prefix in their patterns and routes.
  12. *
  13. * GroupUrlRule is best used by a module which often uses module ID as the prefix for the URL rules.
  14. * For example, the following code creates a rule for the `admin` module:
  15. *
  16. * ```php
  17. * new GroupUrlRule([
  18. * 'prefix' => 'admin',
  19. * 'rules' => [
  20. * 'login' => 'user/login',
  21. * 'logout' => 'user/logout',
  22. * 'dashboard' => 'default/dashboard',
  23. * ],
  24. * ]);
  25. *
  26. * // the above rule is equivalent to the following three rules:
  27. *
  28. * [
  29. * 'admin/login' => 'admin/user/login',
  30. * 'admin/logout' => 'admin/user/logout',
  31. * 'admin/dashboard' => 'admin/default/dashboard',
  32. * ]
  33. * ```
  34. *
  35. * The above example assumes the prefix for patterns and routes are the same. They can be made different
  36. * by configuring [[prefix]] and [[routePrefix]] separately.
  37. *
  38. * Using a GroupUrlRule is more efficient than directly declaring the individual rules it contains.
  39. * This is because GroupUrlRule can quickly determine if it should process a URL parsing or creation request
  40. * by simply checking if the prefix matches.
  41. *
  42. * @author Qiang Xue <qiang.xue@gmail.com>
  43. * @since 2.0
  44. */
  45. class GroupUrlRule extends CompositeUrlRule
  46. {
  47. /**
  48. * @var array the rules contained within this composite rule. Please refer to [[UrlManager::rules]]
  49. * for the format of this property.
  50. * @see prefix
  51. * @see routePrefix
  52. */
  53. public $rules = [];
  54. /**
  55. * @var string the prefix for the pattern part of every rule declared in [[rules]].
  56. * The prefix and the pattern will be separated with a slash.
  57. */
  58. public $prefix;
  59. /**
  60. * @var string the prefix for the route part of every rule declared in [[rules]].
  61. * The prefix and the route will be separated with a slash.
  62. * If this property is not set, it will take the value of [[prefix]].
  63. */
  64. public $routePrefix;
  65. /**
  66. * @var array the default configuration of URL rules. Individual rule configurations
  67. * specified via [[rules]] will take precedence when the same property of the rule is configured.
  68. */
  69. public $ruleConfig = ['class' => 'yii\web\UrlRule'];
  70. /**
  71. * {@inheritdoc}
  72. */
  73. public function init()
  74. {
  75. $this->prefix = trim($this->prefix, '/');
  76. $this->routePrefix = $this->routePrefix === null ? $this->prefix : trim($this->routePrefix, '/');
  77. parent::init();
  78. }
  79. /**
  80. * {@inheritdoc}
  81. */
  82. protected function createRules()
  83. {
  84. $rules = [];
  85. foreach ($this->rules as $key => $rule) {
  86. if (!is_array($rule)) {
  87. $verbs = 'GET|HEAD|POST|PUT|PATCH|DELETE|OPTIONS';
  88. $verb = null;
  89. if (preg_match("/^((?:(?:$verbs),)*(?:$verbs))\\s+(.*)$/", $key, $matches)) {
  90. $verb = explode(',', $matches[1]);
  91. $key = $matches[2];
  92. }
  93. $rule = [
  94. 'pattern' => ltrim($this->prefix . '/' . $key, '/'),
  95. 'route' => ltrim($this->routePrefix . '/' . $rule, '/'),
  96. 'verb' => $verb
  97. ];
  98. } elseif (isset($rule['pattern'], $rule['route'])) {
  99. $rule['pattern'] = ltrim($this->prefix . '/' . $rule['pattern'], '/');
  100. $rule['route'] = ltrim($this->routePrefix . '/' . $rule['route'], '/');
  101. }
  102. $rule = Yii::createObject(array_merge($this->ruleConfig, $rule));
  103. if (!$rule instanceof UrlRuleInterface) {
  104. throw new InvalidConfigException('URL rule class must implement UrlRuleInterface.');
  105. }
  106. $rules[] = $rule;
  107. }
  108. return $rules;
  109. }
  110. /**
  111. * {@inheritdoc}
  112. */
  113. public function parseRequest($manager, $request)
  114. {
  115. $pathInfo = $request->getPathInfo();
  116. if ($this->prefix === '' || strpos($pathInfo . '/', $this->prefix . '/') === 0) {
  117. return parent::parseRequest($manager, $request);
  118. }
  119. return false;
  120. }
  121. /**
  122. * {@inheritdoc}
  123. */
  124. public function createUrl($manager, $route, $params)
  125. {
  126. if ($this->routePrefix === '' || strpos($route, $this->routePrefix . '/') === 0) {
  127. return parent::createUrl($manager, $route, $params);
  128. }
  129. $this->createStatus = UrlRule::CREATE_STATUS_ROUTE_MISMATCH;
  130. return false;
  131. }
  132. }