diff --git a/README.md b/README.md index 1ff3e2b4..97fdd15b 100644 --- a/README.md +++ b/README.md @@ -610,8 +610,8 @@ then the value for `comments` can be ### `x-route` -To customize route (controller ID/action ID) for a path, use custom key `x-route` with value `/`. It can be used for non-crud paths. It must be used under HTTP method key but not -directly under the `paths` key of OpenAPI spec. Example: +To customize [route](https://www.yiiframework.com/doc/guide/2.0/en/runtime-routing) (controller ID/action ID) for a path, use custom key `x-route` with value `[//...]/`. It can be used for non-crud paths. It must be used under HTTP method key but not +directly under the `paths` key of OpenAPI spec. Providing `` and `` is required. Example: ```yaml paths: @@ -681,7 +681,17 @@ Generated URL rules config for above is (in `urls.rest.php` or pertinent file): 'POST a1/b1' => 'abc/xyz', 'a1/b1' => 'abc/options', ``` -`x-route` does not support [Yii Modules](https://www.yiiframework.com/doc/guide/2.0/en/structure-modules). + +`x-route` must not start with slash `/`. For example `x-route: /user/posts` is incorrect. It must start with [module ID](https://www.yiiframework.com/doc/guide/2.0/en/structure-modules) or [controller ID](https://www.yiiframework.com/doc/guide/2.0/en/structure-controllers#controller-ids) + +#### Route, path and namespace + +Route, path and namespace for controller/action will be resolved in following manner (from highest priority to lowest): + +- [`x-route`](#x-route) +- [`urlPrefixes`](https://github.com/php-openapi/yii2-openapi/blob/649743cf0a78743f550edcbd4e93fdffc55c76fd/src/lib/Config.php#L51) +- [`controllerNamespace`](https://github.com/php-openapi/yii2-openapi/blob/649743cf0a78743f550edcbd4e93fdffc55c76fd/src/lib/Config.php#L77) of this lib +- [`controllerNamespace`](https://github.com/yiisoft/yii2/blob/16f50626e1aa81200f109c1a455a5c9b18acfdda/framework/base/Application.php#L93) of Yii app ### `x-description-is-comment` diff --git a/src/lib/Config.php b/src/lib/Config.php index a2531046..ef79bf3c 100644 --- a/src/lib/Config.php +++ b/src/lib/Config.php @@ -183,7 +183,7 @@ public function getOpenApi():OpenApi return $this->openApi; } - public function getPathFromNamespace(string $namespace):string + public static function getPathFromNamespace(string $namespace): string { return Yii::getAlias('@' . str_replace('\\', '/', ltrim($namespace, '\\'))); } diff --git a/src/lib/generators/ControllersGenerator.php b/src/lib/generators/ControllersGenerator.php index ea0c73c4..b10cf734 100644 --- a/src/lib/generators/ControllersGenerator.php +++ b/src/lib/generators/ControllersGenerator.php @@ -18,7 +18,6 @@ use Laminas\Code\Generator\ValueGenerator; use Yii; use yii\gii\CodeFile; -use yii\helpers\ArrayHelper; use yii\helpers\Inflector; class ControllersGenerator @@ -38,7 +37,13 @@ class ControllersGenerator public function __construct(Config $config, array $actions = []) { $this->config = $config; - $this->controllers = ArrayHelper::index($actions, null, 'controllerId'); + foreach ($actions as $action) { + $r = $action->getRoute(); + $r = explode('/', $r); + array_pop($r); + array_pop($r); + $this->controllers[implode('/', $r) . '/' . $action->controllerId][] = $action; + } $this->files = new CodeFiles([]); } @@ -51,22 +56,25 @@ public function generate():CodeFiles return new CodeFiles([]); } $namespace = $this->config->controllerNamespace ?? Yii::$app->controllerNamespace; - $path = $this->config->getPathFromNamespace($namespace); + $path = Config::getPathFromNamespace($namespace); $templateName = $this->config->useJsonApi ? 'controller_jsonapi.php' : 'controller.php'; - foreach ($this->controllers as $controller => $actions) { + foreach ($this->controllers as $controllerWithPrefix => $actions) { $controllerNamespace = $namespace; $controllerPath = $path; /** * @var RestAction|FractalAction $action **/ $action = $actions[0]; - if ($action->prefix && !empty($action->prefixSettings)) { + if (!empty($action->prefixSettings)) { $controllerNamespace = trim($action->prefixSettings['namespace'], '\\'); $controllerPath = $action->prefixSettings['path'] - ?? $this->config->getPathFromNamespace($controllerNamespace); + ?? Config::getPathFromNamespace($controllerNamespace); } - $className = Inflector::id2camel($controller) . 'Controller'; + + $routeParts = explode('/', $controllerWithPrefix); + + $className = Inflector::id2camel(end($routeParts)) . 'Controller'; $this->files->add(new CodeFile( Yii::getAlias($controllerPath . "/base/$className.php"), $this->config->render( @@ -86,6 +94,18 @@ public function generate():CodeFiles $classFileGenerator->generate() )); } + + // generate Module.php file for modules + foreach ($action->modulesList as $moduleId => $moduleDetail) { + // only generate Module.php file if they do not exist, do not override + if (!file_exists(Yii::getAlias($moduleDetail['path'] . "/Module.php"))) { + $moduleFileGenerator = $this->makeModuleFile('Module', $moduleDetail['namespace'], $moduleId, $action); + $this->files->add(new CodeFile( + Yii::getAlias($moduleDetail['path'] . "/Module.php"), + $moduleFileGenerator->generate() + )); + } + } } return $this->files; } @@ -156,4 +176,37 @@ protected function makeCustomController( $classFileGenerator->setClasses([$reflection]); return $classFileGenerator; } + + /** + * @param RestAction|FractalAction $action + */ + public function makeModuleFile(string $class, string $namespace, $moduleId, $action): FileGenerator + { + $file = new FileGenerator; + $reflection = new ClassGenerator( + $class, + $namespace, + null, + 'yii\base\Module' + ); + + $moduleIds = array_keys($action->modulesList); + $position = array_search($moduleId, $moduleIds); + $childModuleId = $childModuleCode = null; + if (array_key_exists($position + 1, $moduleIds)) { # if `true`, child module exists + $childModuleId = $moduleIds[$position + 1]; + $childModuleNamespace = $action->modulesList[$childModuleId]['namespace']; + $childModuleCode = <<modules = [ + '{$childModuleId}' => [ + 'class' => \\{$childModuleNamespace}\Module::class, + ], +]; +PHP; + } + + $reflection->addMethod('init', [], AbstractMemberGenerator::FLAG_PUBLIC, 'parent::init();' . PHP_EOL . $childModuleCode); + $file->setClasses([$reflection]); + return $file; + } } diff --git a/src/lib/generators/JsonActionGenerator.php b/src/lib/generators/JsonActionGenerator.php index 3cc2de2a..a9f38b3f 100644 --- a/src/lib/generators/JsonActionGenerator.php +++ b/src/lib/generators/JsonActionGenerator.php @@ -74,12 +74,19 @@ protected function prepareAction( } } + $actionId = $routeData->isNonCrudAction() ? trim("{$actionType}-{$routeData->action}", '-') + : "$actionType{$routeData->action}"; + if (!empty($customRoute)) { + $parts = explode('/', $customRoute); + $controllerId = $parts[count($parts) - 2]; + $actionId = $parts[count($parts) - 1]; + } + return Yii::createObject(FractalAction::class, [ [ 'singularResourceKey' => $this->config->singularResourceKeys, 'type' => $routeData->type, - 'id' => $routeData->isNonCrudAction() ? trim("{$actionType}-{$routeData->action}", '-') - : "$actionType{$routeData->action}", + 'id' => $actionId, 'controllerId' => $controllerId, 'urlPath' => $routeData->path, 'requestMethod' => strtoupper($method), @@ -96,6 +103,8 @@ protected function prepareAction( 'expectedRelations' => $expectedRelations, 'prefix' => $routeData->getPrefix(), 'prefixSettings' => $routeData->getPrefixSettings(), + 'xRoute' => $customRoute, + 'modulesList' => $routeData->listModules() ], ]); } diff --git a/src/lib/generators/ModelsGenerator.php b/src/lib/generators/ModelsGenerator.php index d2672ff9..2bdbe06f 100644 --- a/src/lib/generators/ModelsGenerator.php +++ b/src/lib/generators/ModelsGenerator.php @@ -46,8 +46,8 @@ public function generate():CodeFiles if (!$this->config->generateModels) { return $this->files; } - $modelPath = $this->config->getPathFromNamespace($this->config->modelNamespace); - $fakerPath = $this->config->getPathFromNamespace($this->config->fakerNamespace); + $modelPath = Config::getPathFromNamespace($this->config->modelNamespace); + $fakerPath = Config::getPathFromNamespace($this->config->fakerNamespace); if ($this->config->generateModelFaker) { $this->files->add(new CodeFile( Yii::getAlias("$fakerPath/BaseModelFaker.php"), diff --git a/src/lib/generators/RestActionGenerator.php b/src/lib/generators/RestActionGenerator.php index b8d5998c..7506d4e0 100644 --- a/src/lib/generators/RestActionGenerator.php +++ b/src/lib/generators/RestActionGenerator.php @@ -71,8 +71,8 @@ protected function resolvePath(string $path, PathItem $pathItem):array { $actions = []; - $routeData = Yii::createObject(RouteData::class, [$pathItem, $path, $this->config->urlPrefixes]); foreach ($pathItem->getOperations() as $method => $operation) { + $routeData = Yii::createObject(RouteData::class, [$path, $pathItem, $method, $operation, $this->config->urlPrefixes]); $customRoute = null; if (isset($operation->{CustomSpecAttr::ROUTE})) { # https://github.com/cebe/yii2-openapi/issues/144 $customRoute = $operation->{CustomSpecAttr::ROUTE}; @@ -119,7 +119,10 @@ protected function prepareAction( $this->knownModelClasses[$routeData->path] = $modelClass; } - if ($routeData->isRelationship()) { + if (!empty($customRoute)) { + $parts = explode('/', $customRoute); + $controllerId = $parts[count($parts) - 2]; + } elseif ($routeData->isRelationship()) { $controllerId = $routeData->controller; $modelClass = Inflector::id2camel(Inflector::singularize($controllerId)); $controllerId = isset($this->config->controllerModelMap[$modelClass]) @@ -129,15 +132,17 @@ protected function prepareAction( $controllerId = isset($this->config->controllerModelMap[$modelClass]) ? Inflector::camel2id($this->config->controllerModelMap[$modelClass]) : Inflector::camel2id($modelClass); - } elseif (!empty($customRoute)) { - $controllerId = explode('/', $customRoute)[0]; } else { $controllerId = $routeData->controller; } $action = Inflector::camel2id($routeData->action); + if (!$action && !$actionType) { + $action = 'index'; + } if (!empty($customRoute)) { $actionType = ''; - $action = explode('/', $customRoute)[1]; + $parts = explode('/', $customRoute); + $action = $parts[count($parts) - 1]; } return Yii::createObject(RestAction::class, [ [ @@ -154,7 +159,9 @@ protected function prepareAction( : null, 'responseWrapper' => $responseWrapper, 'prefix' => $routeData->getPrefix(), - 'prefixSettings' => $routeData->getPrefixSettings() + 'prefixSettings' => $routeData->getPrefixSettings(), + 'xRoute' => $customRoute, + 'modulesList' => $routeData->listModules() ], ]); } diff --git a/src/lib/generators/TransformersGenerator.php b/src/lib/generators/TransformersGenerator.php index 3865ead9..d25aacf5 100644 --- a/src/lib/generators/TransformersGenerator.php +++ b/src/lib/generators/TransformersGenerator.php @@ -48,7 +48,7 @@ public function generate():CodeFiles if (!$this->config->generateControllers || !$this->config->useJsonApi) { return $this->files; } - $transformerPath = $this->config->getPathFromNamespace($this->config->transformerNamespace); + $transformerPath = Config::getPathFromNamespace($this->config->transformerNamespace); foreach ($this->models as $model) { $transformer = Yii::createObject(Transformer::class, [ $model, diff --git a/src/lib/items/OptionsRoutesTrait.php b/src/lib/items/ActionHelperTrait.php similarity index 55% rename from src/lib/items/OptionsRoutesTrait.php rename to src/lib/items/ActionHelperTrait.php index df9e6714..64d6cb38 100644 --- a/src/lib/items/OptionsRoutesTrait.php +++ b/src/lib/items/ActionHelperTrait.php @@ -7,27 +7,36 @@ namespace cebe\yii2openapi\lib\items; -trait OptionsRoutesTrait +trait ActionHelperTrait { + public ?string $xRoute = null; + + # list of module this action is part of. 'key' is module ID and 'value' is path where Module.php file must be generated + public array $modulesList = []; + + /** + * @see $isDuplicate + * https://github.com/cebe/yii2-openapi/issues/84 + * see `x-route` in README.md + * Used for generating only one action for paths like: `GET /calendar/domains` and `GET /calendar/domains/{id}` given that they have same `x-route`. + * If duplicates routes have same params then `false`, else action is generated with no (0) params `true` + */ + public bool $zeroParams = false; + + /** + * https://github.com/cebe/yii2-openapi/issues/84 + * Generate only one action for paths like: `GET /calendar/domains` and `GET /calendar/domains/{id}` given that they have same `x-route`. + * @see $zeroParams + * see `x-route` in README.md + */ + public bool $isDuplicate = false; + public function getOptionsRoute():string { - if ($this->prefix && !empty($this->prefixSettings)) { - if (isset($this->prefixSettings['module'])) { - $prefix = $this->prefixSettings['module']; - return static::finalOptionsRoute($prefix, $this->controllerId); - } elseif (isset($this->prefixSettings['namespace']) && str_contains($this->prefixSettings['namespace'], '\modules\\')) { # if `module` not present then check in namespace and then in path - $prefix = static::computeModule('\\', $this->prefixSettings['namespace']); - if ($prefix) { - return static::finalOptionsRoute($prefix, $this->controllerId); - } - } elseif (isset($this->prefixSettings['path']) && str_contains($this->prefixSettings['path'], '/modules/')) { - $prefix = static::computeModule('/', $this->prefixSettings['path']); - if ($prefix) { - return static::finalOptionsRoute($prefix, $this->controllerId); - } - } - } - return $this->controllerId.'/options'; + $r = $this->getRoute(); + $r = explode('/', $r); + array_pop($r); + return implode('/', $r) . '/options'; } /** @@ -59,4 +68,30 @@ public static function finalOptionsRoute(string $prefix, string $controllerId): { return trim($prefix, '/') . '/' . $controllerId . '/options'; } + + public function getRoute(): string + { + if ($this->xRoute) { + return $this->xRoute; + } + + if (!empty($this->prefixSettings)) { + if (isset($this->prefixSettings['module'])) { + $prefix = $this->prefixSettings['module']; + return trim($prefix, '/') . '/' . $this->controllerId . ($this->id ? '/' . $this->id : ''); + } elseif (isset($this->prefixSettings['namespace']) && str_contains($this->prefixSettings['namespace'], '\modules\\')) { # if `module` not present then check in namespace and then in path + $prefix = static::computeModule('\\', $this->prefixSettings['namespace']); + if ($prefix) { + return trim($prefix, '/') . '/' . $this->controllerId . ($this->id ? '/' . $this->id : ''); + } + } elseif (isset($this->prefixSettings['path']) && str_contains($this->prefixSettings['path'], '/modules/')) { + $prefix = static::computeModule('/', $this->prefixSettings['path']); + if ($prefix) { + return trim($prefix, '/') . '/' . $this->controllerId . ($this->id ? '/' . $this->id : ''); + } + } + } + + return $this->controllerId . ($this->id ? '/' . $this->id : ''); + } } diff --git a/src/lib/items/FractalAction.php b/src/lib/items/FractalAction.php index d95d7d6d..648a2ec0 100644 --- a/src/lib/items/FractalAction.php +++ b/src/lib/items/FractalAction.php @@ -32,7 +32,7 @@ */ final class FractalAction extends BaseObject { - use OptionsRoutesTrait; + use ActionHelperTrait; /**@var string* */ public $id; @@ -95,15 +95,6 @@ private function templateFactory():FractalActionTemplates return $this->templateFactory; } - public function getRoute():string - { - if ($this->prefix && !empty($this->prefixSettings)) { - $prefix = $this->prefixSettings['module'] ?? $this->prefix; - return trim($prefix, '/').'/'.$this->controllerId.'/'.$this->id; - } - return $this->controllerId.'/'.$this->id; - } - public function getBaseModelName():string { return $this->modelFqn ? StringHelper::basename($this->modelFqn) : ''; diff --git a/src/lib/items/RestAction.php b/src/lib/items/RestAction.php index c1f8da90..876889a5 100644 --- a/src/lib/items/RestAction.php +++ b/src/lib/items/RestAction.php @@ -14,7 +14,6 @@ use function array_map; use function implode; use function strtr; -use function trim; use function var_export; /** @@ -31,7 +30,7 @@ */ final class RestAction extends BaseObject { - use OptionsRoutesTrait; + use ActionHelperTrait; /**@var string* */ public $id; @@ -70,33 +69,7 @@ final class RestAction extends BaseObject */ public $responseWrapper; - /** - * @var bool - * @see $isDuplicate - * https://github.com/cebe/yii2-openapi/issues/84 - * see `x-route` in README.md - * Used for generating only one action for paths like: `GET /calendar/domains` and `GET /calendar/domains/{id}` given that they have same `x-route`. - * If duplicates routes have same params then `false`, else action is generated with no (0) params `true` - */ - public $zeroParams = false; - - /** - * @var bool - * https://github.com/cebe/yii2-openapi/issues/84 - * Generate only one action for paths like: `GET /calendar/domains` and `GET /calendar/domains/{id}` given that they have same `x-route`. - * @see $zeroParams - * see `x-route` in README.md - */ - public $isDuplicate = false; - public function getRoute():string - { - if ($this->prefix && !empty($this->prefixSettings)) { - $prefix = $this->prefixSettings['module'] ?? $this->prefix; - return trim($prefix, '/') . '/' . $this->controllerId . '/' . $this->id; - } - return $this->controllerId . '/' . $this->id; - } public function getBaseModelName():string { diff --git a/src/lib/items/RouteData.php b/src/lib/items/RouteData.php index e50ab37a..b78e00ec 100644 --- a/src/lib/items/RouteData.php +++ b/src/lib/items/RouteData.php @@ -7,7 +7,10 @@ namespace cebe\yii2openapi\lib\items; +use cebe\openapi\spec\Operation; use cebe\openapi\spec\PathItem; +use cebe\yii2openapi\lib\Config; +use cebe\yii2openapi\lib\CustomSpecAttr; use yii\base\BaseObject; use yii\base\InvalidCallException; use yii\helpers\ArrayHelper; @@ -164,12 +167,57 @@ final class RouteData extends BaseObject */ private $urlPrefixes; - public function __construct(PathItem $pathItem, string $path, array $urlPrefixes = [], $config = []) - { + /** + * @var string + */ + private $method; + + /** + * @var Operation + */ + private $operation; + + private $moduleList = []; + + public function __construct( + string $path, + PathItem $pathItem, + string $method, + Operation $operation, + array $urlPrefixes = [], + $config = [] + ) { $this->path = $this->unprefixedPath = $path; $this->parts = explode('/', trim($path, '/')); $this->pathItem = $pathItem; + $this->method = $method; + $this->operation = $operation; $this->urlPrefixes = $urlPrefixes; + + if (isset($operation->{CustomSpecAttr::ROUTE})) { # https://github.com/cebe/yii2-openapi/issues/144 + $customRoute = $operation->{CustomSpecAttr::ROUTE}; + $parts = explode('/', $customRoute); + array_pop($parts); + array_pop($parts); + + $modulesPathSection = $modulesPath = []; + $container = $modulesNamespaceSection = ''; + foreach ($parts as $moduleId) { + $modulesPathSection[$moduleId] = 'modules/' . $moduleId; + $container .= ($container !== '' ? '/' : '') . ('modules/' . $moduleId); + $modulesNamespaceSection .= ($modulesNamespaceSection ? '\\' : '') . ($moduleId); + $modulesPath[$moduleId] = ['path' => '@app/' . $container, 'namespace' => 'app\\' . $modulesNamespaceSection]; + } + $this->moduleList = $modulesPath; + + if ($parts) { + $this->prefixSettings = [ + 'namespace' => 'app\\' . implode('\\', $parts) . '\\controllers', + 'path' => '@app/' . implode('/', $modulesPathSection) . '/controllers' + ]; + } + } + parent::__construct($config); } @@ -227,7 +275,7 @@ public function init() } $this->pattern = implode('/', $patternParts); if ($this->prefix) { - $this->pattern = trim($this->prefix, '/').'/'.$this->pattern; + $this->pattern = trim($this->prefix, '/') . ($this->pattern ? '/' . $this->pattern : ''); } if ($this->hasParams && $this->isRelationship()) { $this->relatedModel = $this->getFirstParam()['model'] ?? null; @@ -264,8 +312,15 @@ protected function detectUrlPattern():void $this->type = self::TYPE_DEFAULT; $this->action = ''; $this->controller = 'default'; + if (isset($this->operation->{CustomSpecAttr::ROUTE})) { # https://github.com/cebe/yii2-openapi/issues/144 + $customRoute = $this->operation->{CustomSpecAttr::ROUTE}; + $parts = explode('/', $customRoute); + $this->action = array_pop($parts); + $this->controller = array_pop($parts); + } return; } + foreach ($this->urlPrefixes as $prefix => $rule) { if (!str_starts_with(trim($this->path, '/'), trim($prefix, '/'))) { continue; @@ -274,6 +329,20 @@ protected function detectUrlPattern():void $this->unprefixedPath = '/' . trim(str_replace($prefix, '', $this->path), '/'); $this->parts = explode('/', trim($this->unprefixedPath, '/')); $this->prefixSettings = is_array($rule) ? $rule : []; + + $modulesPath = []; + if (isset($rule['module'])) { + $modPath = $rule['path'] ?? Config::getPathFromNamespace($rule['namespace']); + if (str_ends_with($modPath, '/controllers')) { + $modPath = substr($modPath, 0, -12); + } + $modNs = $rule['namespace']; + if (str_ends_with($modNs, '\controllers')) { + $modNs = substr($modNs, 0, -12); + } + $modulesPath[$rule['module']] = ['path' => $modPath, 'namespace' => $modNs]; + } + $this->moduleList = array_merge($this->moduleList, $modulesPath); } foreach (self::$patternMap as $type => $pattern) { if (preg_match($pattern, $this->unprefixedPath, $matches)) { @@ -432,4 +501,12 @@ public function isNonCrudAction():bool { return in_array($this->type, [self::TYPE_DEFAULT, self::TYPE_RESOURCE_OPERATION]); } + + /** + * Returns list of modules this action is part of + */ + public function listModules(): array + { + return $this->moduleList; + } } diff --git a/tests/specs/issue_fix/14_module_config_in_url_prefixes/fractal/abc/Module.php b/tests/specs/issue_fix/14_module_config_in_url_prefixes/fractal/abc/Module.php new file mode 100644 index 00000000..d8db2760 --- /dev/null +++ b/tests/specs/issue_fix/14_module_config_in_url_prefixes/fractal/abc/Module.php @@ -0,0 +1,15 @@ + [ + 'class' => \insolita\fractal\actions\ViewAction::class, + 'checkAccess' => [$this, 'checkAccess'], + 'transformer' => \app\transformers\TaskTransformer::class, + 'modelClass' => \app\models\Task::class, + 'resourceKey' => 'tasks', + 'findModel' => null + ], + 'options' => [ + 'class' => \yii\rest\OptionsAction::class, + ], + ]; + } + + /** + * Checks the privilege of the current user. + * + * This method checks whether the current user has the privilege + * to run the specified action against the specified data model. + * If the user does not have access, a [[ForbiddenHttpException]] should be thrown. + * + * @param string $action the ID of the action to be executed + * @param object $model the model to be accessed. If null, it means no specific model is being accessed. + * @param array $params additional parameters + * @throws \yii\web\ForbiddenHttpException if the user does not have access + */ + abstract public function checkAccess($action, $model = null, $params = []); +} diff --git a/tests/specs/issue_fix/14_module_config_in_url_prefixes/fractal/config/urls.rest.php b/tests/specs/issue_fix/14_module_config_in_url_prefixes/fractal/config/urls.rest.php new file mode 100644 index 00000000..ff8f9f84 --- /dev/null +++ b/tests/specs/issue_fix/14_module_config_in_url_prefixes/fractal/config/urls.rest.php @@ -0,0 +1,15 @@ + 'greet/default', + 'GET bye' => 'bye/list', + 'POST bye' => 'bye/create', + 'GET abc/task/' => 'abc/task/view', + 'hi' => 'greet/options', + 'bye' => 'bye/options', + 'abc/task/' => 'abc/task/options', +]; diff --git a/tests/specs/issue_fix/14_module_config_in_url_prefixes/fractal/controllers/ByeController.php b/tests/specs/issue_fix/14_module_config_in_url_prefixes/fractal/controllers/ByeController.php new file mode 100644 index 00000000..637a6b7a --- /dev/null +++ b/tests/specs/issue_fix/14_module_config_in_url_prefixes/fractal/controllers/ByeController.php @@ -0,0 +1,31 @@ + [ + 'class' => \yii\rest\OptionsAction::class, + ], + ]; + } + + /** + * Checks the privilege of the current user. + * + * This method checks whether the current user has the privilege + * to run the specified action against the specified data model. + * If the user does not have access, a [[ForbiddenHttpException]] should be thrown. + * + * @param string $action the ID of the action to be executed + * @param object $model the model to be accessed. If null, it means no specific model is being accessed. + * @param array $params additional parameters + * @throws \yii\web\ForbiddenHttpException if the user does not have access + */ + abstract public function checkAccess($action, $model = null, $params = []); + + abstract public function actionList(); + + abstract public function actionCreate(); +} diff --git a/tests/specs/issue_fix/14_module_config_in_url_prefixes/fractal/greet/DefaultController.php b/tests/specs/issue_fix/14_module_config_in_url_prefixes/fractal/greet/DefaultController.php new file mode 100644 index 00000000..f96d55eb --- /dev/null +++ b/tests/specs/issue_fix/14_module_config_in_url_prefixes/fractal/greet/DefaultController.php @@ -0,0 +1,26 @@ + [ + 'class' => \yii\rest\OptionsAction::class, + ], + ]; + } + + /** + * Checks the privilege of the current user. + * + * This method checks whether the current user has the privilege + * to run the specified action against the specified data model. + * If the user does not have access, a [[ForbiddenHttpException]] should be thrown. + * + * @param string $action the ID of the action to be executed + * @param object $model the model to be accessed. If null, it means no specific model is being accessed. + * @param array $params additional parameters + * @throws \yii\web\ForbiddenHttpException if the user does not have access + */ + abstract public function checkAccess($action, $model = null, $params = []); + + abstract public function action(); +} diff --git a/tests/specs/issue_fix/14_module_config_in_url_prefixes/fractal/models/Task.php b/tests/specs/issue_fix/14_module_config_in_url_prefixes/fractal/models/Task.php new file mode 100644 index 00000000..9d6a9e04 --- /dev/null +++ b/tests/specs/issue_fix/14_module_config_in_url_prefixes/fractal/models/Task.php @@ -0,0 +1,10 @@ + [['title'], 'trim'], + 'title_string' => [['title'], 'string'], + ]; + } +} diff --git a/tests/specs/issue_fix/14_module_config_in_url_prefixes/fractal/transformers/TaskTransformer.php b/tests/specs/issue_fix/14_module_config_in_url_prefixes/fractal/transformers/TaskTransformer.php new file mode 100644 index 00000000..8d0433a8 --- /dev/null +++ b/tests/specs/issue_fix/14_module_config_in_url_prefixes/fractal/transformers/TaskTransformer.php @@ -0,0 +1,10 @@ +getAttributes(); + } +} diff --git a/tests/specs/issue_fix/14_module_config_in_url_prefixes/index.php b/tests/specs/issue_fix/14_module_config_in_url_prefixes/index.php new file mode 100644 index 00000000..97759622 --- /dev/null +++ b/tests/specs/issue_fix/14_module_config_in_url_prefixes/index.php @@ -0,0 +1,17 @@ + '@specs/issue_fix/14_module_config_in_url_prefixes/index.yml', + 'generateUrls' => true, + 'generateModels' => true, + 'excludeModels' => [ + 'Error', + ], + 'generateControllers' => true, + 'generateMigrations' => false, + 'generateModelFaker' => false, + 'urlPrefixes' => [ + 'hi' => ['module' => 'greet', 'namespace' => 'app\greet'], + 'abc' => ['module' => 'abc', 'namespace' => 'app\abc'], + ] +]; diff --git a/tests/specs/issue_fix/14_module_config_in_url_prefixes/index.yml b/tests/specs/issue_fix/14_module_config_in_url_prefixes/index.yml new file mode 100644 index 00000000..8a20f1bd --- /dev/null +++ b/tests/specs/issue_fix/14_module_config_in_url_prefixes/index.yml @@ -0,0 +1,96 @@ +openapi: "3.0.0" +info: + version: 1.0.0 + title: Issue14Test 14_module_config_in_url_prefixes \#14 + +paths: + /hi: + get: + summary: List + operationId: list + responses: + '200': + description: The information + /bye: + get: + summary: List + operationId: list + responses: + '200': + description: The information + post: + summary: List + operationId: list + responses: + '200': + description: The information + '/abc/task/{id}': + parameters: + - name: id + in: path + description: ID of the task. + required: true + schema: + type: integer + get: + operationId: getTask + summary: Get a Task by ID + description: Returns a single task by its unique ID. + responses: + '200': + $ref: '#/components/responses/Task' + '403': + description: Response if the currently authenticated user has no access to this task. + '404': + description: Response if the task does not exist. + tags: + - Tasks + +components: + schemas: + _TaskResource: + type: object + properties: + id: + type: integer + example: 1 + type: + type: string + enum: + - tasks + attributes: + $ref: '#/components/schemas/Task' + relationships: + type: object + JSONAPI_links: + type: object + example: + self: 'https://api.example.com/...' + additionalProperties: + oneOf: + - type: string + - type: object + properties: + href: + type: string + meta: + type: object + Task: + type: object + properties: + id: + type: integer + title: + type: string + responses: + Task: + description: Task + content: + application/vnd.api+json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/_TaskResource' + links: + $ref: '#/components/schemas/JSONAPI_links' diff --git a/tests/specs/issue_fix/14_module_config_in_url_prefixes/mysql/abc/Module.php b/tests/specs/issue_fix/14_module_config_in_url_prefixes/mysql/abc/Module.php new file mode 100644 index 00000000..d8db2760 --- /dev/null +++ b/tests/specs/issue_fix/14_module_config_in_url_prefixes/mysql/abc/Module.php @@ -0,0 +1,15 @@ + [ + 'class' => \yii\rest\ViewAction::class, + 'modelClass' => \app\models\Task::class, + 'checkAccess' => [$this, 'checkAccess'], + ], + 'options' => [ + 'class' => \yii\rest\OptionsAction::class, + ], + ]; + } + + /** + * Checks the privilege of the current user. + * + * This method checks whether the current user has the privilege + * to run the specified action against the specified data model. + * If the user does not have access, a [[ForbiddenHttpException]] should be thrown. + * + * @param string $action the ID of the action to be executed + * @param object $model the model to be accessed. If null, it means no specific model is being accessed. + * @param array $params additional parameters + * @throws \yii\web\ForbiddenHttpException if the user does not have access + */ + abstract public function checkAccess($action, $model = null, $params = []); + +} diff --git a/tests/specs/issue_fix/14_module_config_in_url_prefixes/mysql/config/urls.rest.php b/tests/specs/issue_fix/14_module_config_in_url_prefixes/mysql/config/urls.rest.php new file mode 100644 index 00000000..9b2b36f6 --- /dev/null +++ b/tests/specs/issue_fix/14_module_config_in_url_prefixes/mysql/config/urls.rest.php @@ -0,0 +1,15 @@ + 'greet/default/index', + 'GET bye' => 'bye/list', + 'POST bye' => 'bye/create', + 'GET abc/task/' => 'abc/task/view', + 'hi' => 'greet/default/options', + 'bye' => 'bye/options', + 'abc/task/' => 'abc/task/options', +]; diff --git a/tests/specs/issue_fix/14_module_config_in_url_prefixes/mysql/controllers/ByeController.php b/tests/specs/issue_fix/14_module_config_in_url_prefixes/mysql/controllers/ByeController.php new file mode 100644 index 00000000..f58e5aac --- /dev/null +++ b/tests/specs/issue_fix/14_module_config_in_url_prefixes/mysql/controllers/ByeController.php @@ -0,0 +1,25 @@ + [ + 'class' => \yii\rest\OptionsAction::class, + ], + ]; + } + + /** + * Checks the privilege of the current user. + * + * This method checks whether the current user has the privilege + * to run the specified action against the specified data model. + * If the user does not have access, a [[ForbiddenHttpException]] should be thrown. + * + * @param string $action the ID of the action to be executed + * @param object $model the model to be accessed. If null, it means no specific model is being accessed. + * @param array $params additional parameters + * @throws \yii\web\ForbiddenHttpException if the user does not have access + */ + abstract public function checkAccess($action, $model = null, $params = []); + + abstract public function actionList(); + + abstract public function actionCreate(); + +} diff --git a/tests/specs/issue_fix/14_module_config_in_url_prefixes/mysql/greet/DefaultController.php b/tests/specs/issue_fix/14_module_config_in_url_prefixes/mysql/greet/DefaultController.php new file mode 100644 index 00000000..958a7fa6 --- /dev/null +++ b/tests/specs/issue_fix/14_module_config_in_url_prefixes/mysql/greet/DefaultController.php @@ -0,0 +1,20 @@ + [ + 'class' => \yii\rest\OptionsAction::class, + ], + ]; + } + + /** + * Checks the privilege of the current user. + * + * This method checks whether the current user has the privilege + * to run the specified action against the specified data model. + * If the user does not have access, a [[ForbiddenHttpException]] should be thrown. + * + * @param string $action the ID of the action to be executed + * @param object $model the model to be accessed. If null, it means no specific model is being accessed. + * @param array $params additional parameters + * @throws \yii\web\ForbiddenHttpException if the user does not have access + */ + abstract public function checkAccess($action, $model = null, $params = []); + + abstract public function actionIndex(); + +} diff --git a/tests/specs/issue_fix/14_module_config_in_url_prefixes/mysql/models/Task.php b/tests/specs/issue_fix/14_module_config_in_url_prefixes/mysql/models/Task.php new file mode 100644 index 00000000..9d6a9e04 --- /dev/null +++ b/tests/specs/issue_fix/14_module_config_in_url_prefixes/mysql/models/Task.php @@ -0,0 +1,10 @@ + [['title'], 'trim'], + 'title_string' => [['title'], 'string'], + ]; + } +} diff --git a/tests/specs/issue_fix/14_nested_module_in_x_route/fractal/config/urls.rest.php b/tests/specs/issue_fix/14_nested_module_in_x_route/fractal/config/urls.rest.php new file mode 100644 index 00000000..a37f99ee --- /dev/null +++ b/tests/specs/issue_fix/14_nested_module_in_x_route/fractal/config/urls.rest.php @@ -0,0 +1,12 @@ + 'fruit/mango/alphonso/list', + 'GET task/' => 'fruit2/mango/alphonso/view', + 'tasks' => 'fruit/mango/alphonso/options', + 'task/' => 'fruit2/mango/alphonso/options', +]; diff --git a/tests/specs/issue_fix/14_nested_module_in_x_route/fractal/models/Task.php b/tests/specs/issue_fix/14_nested_module_in_x_route/fractal/models/Task.php new file mode 100644 index 00000000..9d6a9e04 --- /dev/null +++ b/tests/specs/issue_fix/14_nested_module_in_x_route/fractal/models/Task.php @@ -0,0 +1,10 @@ + [['title'], 'trim'], + 'title_string' => [['title'], 'string'], + ]; + } +} diff --git a/tests/specs/issue_fix/14_nested_module_in_x_route/fractal/modules/fruit/Module.php b/tests/specs/issue_fix/14_nested_module_in_x_route/fractal/modules/fruit/Module.php new file mode 100644 index 00000000..f29b749c --- /dev/null +++ b/tests/specs/issue_fix/14_nested_module_in_x_route/fractal/modules/fruit/Module.php @@ -0,0 +1,20 @@ +modules = [ + 'mango' => [ + 'class' => \app\fruit\mango\Module::class, + ], + ]; + } + + +} + diff --git a/tests/specs/issue_fix/14_nested_module_in_x_route/fractal/modules/fruit/modules/mango/Module.php b/tests/specs/issue_fix/14_nested_module_in_x_route/fractal/modules/fruit/modules/mango/Module.php new file mode 100644 index 00000000..e0e13d8f --- /dev/null +++ b/tests/specs/issue_fix/14_nested_module_in_x_route/fractal/modules/fruit/modules/mango/Module.php @@ -0,0 +1,15 @@ + [ + 'class' => \insolita\fractal\actions\ListAction::class, + 'checkAccess' => [$this, 'checkAccess'], + 'transformer' => \app\transformers\TaskTransformer::class, + 'modelClass' => \app\models\Task::class, + 'resourceKey' => 'tasks', + 'dataFilter' => null, + 'prepareDataProvider' => null + ], + 'options' => [ + 'class' => \yii\rest\OptionsAction::class, + ], + ]; + } + + /** + * Checks the privilege of the current user. + * + * This method checks whether the current user has the privilege + * to run the specified action against the specified data model. + * If the user does not have access, a [[ForbiddenHttpException]] should be thrown. + * + * @param string $action the ID of the action to be executed + * @param object $model the model to be accessed. If null, it means no specific model is being accessed. + * @param array $params additional parameters + * @throws \yii\web\ForbiddenHttpException if the user does not have access + */ + abstract public function checkAccess($action, $model = null, $params = []); +} diff --git a/tests/specs/issue_fix/14_nested_module_in_x_route/fractal/modules/fruit2/Module.php b/tests/specs/issue_fix/14_nested_module_in_x_route/fractal/modules/fruit2/Module.php new file mode 100644 index 00000000..6a82f0e9 --- /dev/null +++ b/tests/specs/issue_fix/14_nested_module_in_x_route/fractal/modules/fruit2/Module.php @@ -0,0 +1,20 @@ +modules = [ + 'mango' => [ + 'class' => \app\fruit2\mango\Module::class, + ], + ]; + } + + +} + diff --git a/tests/specs/issue_fix/14_nested_module_in_x_route/fractal/modules/fruit2/modules/mango/Module.php b/tests/specs/issue_fix/14_nested_module_in_x_route/fractal/modules/fruit2/modules/mango/Module.php new file mode 100644 index 00000000..87f692cb --- /dev/null +++ b/tests/specs/issue_fix/14_nested_module_in_x_route/fractal/modules/fruit2/modules/mango/Module.php @@ -0,0 +1,15 @@ + [ + 'class' => \insolita\fractal\actions\ViewAction::class, + 'checkAccess' => [$this, 'checkAccess'], + 'transformer' => \app\transformers\TaskTransformer::class, + 'modelClass' => \app\models\Task::class, + 'resourceKey' => 'tasks', + 'findModel' => null + ], + 'options' => [ + 'class' => \yii\rest\OptionsAction::class, + ], + ]; + } + + /** + * Checks the privilege of the current user. + * + * This method checks whether the current user has the privilege + * to run the specified action against the specified data model. + * If the user does not have access, a [[ForbiddenHttpException]] should be thrown. + * + * @param string $action the ID of the action to be executed + * @param object $model the model to be accessed. If null, it means no specific model is being accessed. + * @param array $params additional parameters + * @throws \yii\web\ForbiddenHttpException if the user does not have access + */ + abstract public function checkAccess($action, $model = null, $params = []); +} diff --git a/tests/specs/issue_fix/14_nested_module_in_x_route/fractal/transformers/TaskTransformer.php b/tests/specs/issue_fix/14_nested_module_in_x_route/fractal/transformers/TaskTransformer.php new file mode 100644 index 00000000..8d0433a8 --- /dev/null +++ b/tests/specs/issue_fix/14_nested_module_in_x_route/fractal/transformers/TaskTransformer.php @@ -0,0 +1,10 @@ +getAttributes(); + } +} diff --git a/tests/specs/issue_fix/14_nested_module_in_x_route/index.php b/tests/specs/issue_fix/14_nested_module_in_x_route/index.php new file mode 100644 index 00000000..a9990a13 --- /dev/null +++ b/tests/specs/issue_fix/14_nested_module_in_x_route/index.php @@ -0,0 +1,13 @@ + '@specs/issue_fix/14_nested_module_in_x_route/index.yml', + 'generateUrls' => true, + 'generateModels' => true, + 'excludeModels' => [ + 'Error', + ], + 'generateControllers' => true, + 'generateMigrations' => false, + 'generateModelFaker' => false, +]; diff --git a/tests/specs/issue_fix/14_nested_module_in_x_route/index.yml b/tests/specs/issue_fix/14_nested_module_in_x_route/index.yml new file mode 100644 index 00000000..e87a85de --- /dev/null +++ b/tests/specs/issue_fix/14_nested_module_in_x_route/index.yml @@ -0,0 +1,98 @@ +openapi: "3.0.0" +info: + version: 1.0.0 + title: Issue14Test testNestedModuleInXRoute \#14 + +paths: + '/tasks': + get: + x-route: fruit/mango/alphonso/list # action ID `list` is mandatory for fractal standalone action generation + operationId: listTasks + responses: + '200': + $ref: '#/components/responses/Tasks' + + '/task/{id}': + parameters: + - name: id + in: path + description: ID of the task. + required: true + schema: + type: integer + get: + x-route: fruit2/mango/alphonso/view # action ID `view` is mandatory for fractal standalone action generation + operationId: getTask + summary: Get a Task by ID + description: Returns a single task by its unique ID. + responses: + '200': + $ref: '#/components/responses/Task' + '403': + description: Response if the currently authenticated user has no access to this task. + '404': + description: Response if the task does not exist. + tags: + - Tasks + +components: + schemas: + _TaskResource: + type: object + properties: + id: + type: integer + example: 1 + type: + type: string + enum: + - tasks + attributes: + $ref: '#/components/schemas/Task' + relationships: + type: object + JSONAPI_links: + type: object + example: + self: 'https://api.example.com/...' + additionalProperties: + oneOf: + - type: string + - type: object + properties: + href: + type: string + meta: + type: object + Task: + type: object + properties: + id: + type: integer + title: + type: string + responses: + Task: + description: Task + content: + application/vnd.api+json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/_TaskResource' + links: + $ref: '#/components/schemas/JSONAPI_links' + Tasks: + description: 'An array of Tasks' + content: + application/vnd.api+json: + schema: + type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/_TaskResource' + links: + $ref: '#/components/schemas/JSONAPI_links' diff --git a/tests/specs/issue_fix/14_nested_module_in_x_route/mysql/config/urls.rest.php b/tests/specs/issue_fix/14_nested_module_in_x_route/mysql/config/urls.rest.php new file mode 100644 index 00000000..a37f99ee --- /dev/null +++ b/tests/specs/issue_fix/14_nested_module_in_x_route/mysql/config/urls.rest.php @@ -0,0 +1,12 @@ + 'fruit/mango/alphonso/list', + 'GET task/' => 'fruit2/mango/alphonso/view', + 'tasks' => 'fruit/mango/alphonso/options', + 'task/' => 'fruit2/mango/alphonso/options', +]; diff --git a/tests/specs/issue_fix/14_nested_module_in_x_route/mysql/models/Task.php b/tests/specs/issue_fix/14_nested_module_in_x_route/mysql/models/Task.php new file mode 100644 index 00000000..9d6a9e04 --- /dev/null +++ b/tests/specs/issue_fix/14_nested_module_in_x_route/mysql/models/Task.php @@ -0,0 +1,10 @@ + [['title'], 'trim'], + 'title_string' => [['title'], 'string'], + ]; + } +} diff --git a/tests/specs/issue_fix/14_nested_module_in_x_route/mysql/modules/fruit/Module.php b/tests/specs/issue_fix/14_nested_module_in_x_route/mysql/modules/fruit/Module.php new file mode 100644 index 00000000..f29b749c --- /dev/null +++ b/tests/specs/issue_fix/14_nested_module_in_x_route/mysql/modules/fruit/Module.php @@ -0,0 +1,20 @@ +modules = [ + 'mango' => [ + 'class' => \app\fruit\mango\Module::class, + ], + ]; + } + + +} + diff --git a/tests/specs/issue_fix/14_nested_module_in_x_route/mysql/modules/fruit/modules/mango/Module.php b/tests/specs/issue_fix/14_nested_module_in_x_route/mysql/modules/fruit/modules/mango/Module.php new file mode 100644 index 00000000..e0e13d8f --- /dev/null +++ b/tests/specs/issue_fix/14_nested_module_in_x_route/mysql/modules/fruit/modules/mango/Module.php @@ -0,0 +1,15 @@ + [ + 'class' => \yii\rest\IndexAction::class, + 'modelClass' => \app\models\Task::class, + 'checkAccess' => [$this, 'checkAccess'], + ], + 'options' => [ + 'class' => \yii\rest\OptionsAction::class, + ], + ]; + } + + /** + * Checks the privilege of the current user. + * + * This method checks whether the current user has the privilege + * to run the specified action against the specified data model. + * If the user does not have access, a [[ForbiddenHttpException]] should be thrown. + * + * @param string $action the ID of the action to be executed + * @param object $model the model to be accessed. If null, it means no specific model is being accessed. + * @param array $params additional parameters + * @throws \yii\web\ForbiddenHttpException if the user does not have access + */ + abstract public function checkAccess($action, $model = null, $params = []); + +} diff --git a/tests/specs/issue_fix/14_nested_module_in_x_route/mysql/modules/fruit2/Module.php b/tests/specs/issue_fix/14_nested_module_in_x_route/mysql/modules/fruit2/Module.php new file mode 100644 index 00000000..6a82f0e9 --- /dev/null +++ b/tests/specs/issue_fix/14_nested_module_in_x_route/mysql/modules/fruit2/Module.php @@ -0,0 +1,20 @@ +modules = [ + 'mango' => [ + 'class' => \app\fruit2\mango\Module::class, + ], + ]; + } + + +} + diff --git a/tests/specs/issue_fix/14_nested_module_in_x_route/mysql/modules/fruit2/modules/mango/Module.php b/tests/specs/issue_fix/14_nested_module_in_x_route/mysql/modules/fruit2/modules/mango/Module.php new file mode 100644 index 00000000..87f692cb --- /dev/null +++ b/tests/specs/issue_fix/14_nested_module_in_x_route/mysql/modules/fruit2/modules/mango/Module.php @@ -0,0 +1,15 @@ + [ + 'class' => \yii\rest\ViewAction::class, + 'modelClass' => \app\models\Task::class, + 'checkAccess' => [$this, 'checkAccess'], + ], + 'options' => [ + 'class' => \yii\rest\OptionsAction::class, + ], + ]; + } + + /** + * Checks the privilege of the current user. + * + * This method checks whether the current user has the privilege + * to run the specified action against the specified data model. + * If the user does not have access, a [[ForbiddenHttpException]] should be thrown. + * + * @param string $action the ID of the action to be executed + * @param object $model the model to be accessed. If null, it means no specific model is being accessed. + * @param array $params additional parameters + * @throws \yii\web\ForbiddenHttpException if the user does not have access + */ + abstract public function checkAccess($action, $model = null, $params = []); + +} diff --git a/tests/specs/issue_fix/35_resolve_todo_re_check_options_route_in_fractal_action/index.php b/tests/specs/issue_fix/35_resolve_todo_re_check_options_route_in_fractal_action/index.php index f4e7c94b..2599e4e1 100644 --- a/tests/specs/issue_fix/35_resolve_todo_re_check_options_route_in_fractal_action/index.php +++ b/tests/specs/issue_fix/35_resolve_todo_re_check_options_route_in_fractal_action/index.php @@ -9,13 +9,13 @@ ], 'generateControllers' => true, 'generateMigrations' => false, - 'useJsonApi' => false, + 'useJsonApi' => true, 'urlPrefixes' => [ 'animals' => '', '/info' => ['module' => 'petinfo', 'namespace' => '\app\modules\petinfo\controllers'], '/forum' => ['namespace' => '\app\modules\forum\controllers'], # namespace contains "\modules\" '/forum2' => ['path' => '@app/modules/forum2/controllers', 'namespace' => '\app\forum2\controllers'], # path contains "/modules/" - '/api/v1' => ['path' => '@app/modules/some/controllers', 'namespace' => '\app\api\v1\controllers'], # namespace contains "\modules\"; module will be "api/v1" - '/api/v2' => ['path' => '@app/modules/api/v2/controllers', 'namespace' => '\app\some\controllers'], # namespace contains "\modules\"; module will be "api/v2" + '/api/v1' => ['path' => '@app/modules/some/controllers', 'namespace' => '\app\api\v1\controllers'], + '/api/v2' => ['path' => '@app/modules/api/v2/controllers', 'namespace' => '\app\some\controllers'], ] ]; diff --git a/tests/specs/issue_fix/35_resolve_todo_re_check_options_route_in_fractal_action/mysql/config/urls.rest.php b/tests/specs/issue_fix/35_resolve_todo_re_check_options_route_in_fractal_action/mysql/config/urls.rest.php index fb1998ac..14a0ef55 100644 --- a/tests/specs/issue_fix/35_resolve_todo_re_check_options_route_in_fractal_action/mysql/config/urls.rest.php +++ b/tests/specs/issue_fix/35_resolve_todo_re_check_options_route_in_fractal_action/mysql/config/urls.rest.php @@ -5,8 +5,8 @@ * This file is auto generated. */ return [ - 'GET api/v1/pets' => 'api/v1/pet/list', - 'POST api/v1/pets' => 'api/v1/pet/create', + 'GET api/v1/pets' => 'some/pet/list', + 'POST api/v1/pets' => 'some/pet/create', 'GET animals/pets/' => 'pet/view', 'DELETE animals/pets/' => 'pet/delete', 'PATCH animals/pets/' => 'pet/update', diff --git a/tests/specs/issue_fix/35_resolve_todo_re_check_options_route_in_fractal_action/mysql/controllers/PetCommentController.php b/tests/specs/issue_fix/35_resolve_todo_re_check_options_route_in_fractal_action/mysql/controllers/PetCommentController.php index b71a5cb0..560e0858 100644 --- a/tests/specs/issue_fix/35_resolve_todo_re_check_options_route_in_fractal_action/mysql/controllers/PetCommentController.php +++ b/tests/specs/issue_fix/35_resolve_todo_re_check_options_route_in_fractal_action/mysql/controllers/PetCommentController.php @@ -5,6 +5,12 @@ class PetCommentController extends \app\controllers\base\PetCommentController { + public function actions() + { + $actions = parent::actions(); + return $actions; + } + public function checkAccess($action, $model = null, $params = []) { //TODO implement checkAccess diff --git a/tests/specs/issue_fix/35_resolve_todo_re_check_options_route_in_fractal_action/mysql/controllers/PetController.php b/tests/specs/issue_fix/35_resolve_todo_re_check_options_route_in_fractal_action/mysql/controllers/PetController.php new file mode 100644 index 00000000..a0a80b74 --- /dev/null +++ b/tests/specs/issue_fix/35_resolve_todo_re_check_options_route_in_fractal_action/mysql/controllers/PetController.php @@ -0,0 +1,21 @@ + [ + 'class' => \insolita\fractal\actions\ViewAction::class, + 'checkAccess' => [$this, 'checkAccess'], + 'transformer' => \app\transformers\PetTransformer::class, + 'modelClass' => \app\models\Pet::class, + 'resourceKey' => 'pets', + 'findModel' => null + ], + 'delete' => [ + 'class' => \insolita\fractal\actions\DeleteAction::class, + 'checkAccess' => [$this, 'checkAccess'], + 'modelClass' => \app\models\Pet::class, + 'findModel' => null + ], + 'update' => [ + 'class' => \insolita\fractal\actions\UpdateAction::class, + 'checkAccess' => [$this, 'checkAccess'], + 'transformer' => \app\transformers\PetTransformer::class, + 'modelClass' => \app\models\Pet::class, + 'resourceKey' => 'pets', + 'findModel' => null, + 'allowedRelations'=>[], + 'scenario' => 'default' + ], + 'options' => [ + 'class' => \yii\rest\OptionsAction::class, + ], + ]; + } + + /** + * Checks the privilege of the current user. + * + * This method checks whether the current user has the privilege + * to run the specified action against the specified data model. + * If the user does not have access, a [[ForbiddenHttpException]] should be thrown. + * + * @param string $action the ID of the action to be executed + * @param object $model the model to be accessed. If null, it means no specific model is being accessed. + * @param array $params additional parameters + * @throws \yii\web\ForbiddenHttpException if the user does not have access + */ + abstract public function checkAccess($action, $model = null, $params = []); +} diff --git a/tests/specs/issue_fix/35_resolve_todo_re_check_options_route_in_fractal_action/mysql/modules/api/v2/controllers/CommentController.php b/tests/specs/issue_fix/35_resolve_todo_re_check_options_route_in_fractal_action/mysql/modules/api/v2/controllers/CommentController.php index 55b0bc54..c0c562ad 100644 --- a/tests/specs/issue_fix/35_resolve_todo_re_check_options_route_in_fractal_action/mysql/modules/api/v2/controllers/CommentController.php +++ b/tests/specs/issue_fix/35_resolve_todo_re_check_options_route_in_fractal_action/mysql/modules/api/v2/controllers/CommentController.php @@ -5,6 +5,12 @@ class CommentController extends \app\some\controllers\base\CommentController { + public function actions() + { + $actions = parent::actions(); + return $actions; + } + public function checkAccess($action, $model = null, $params = []) { //TODO implement checkAccess diff --git a/tests/specs/issue_fix/35_resolve_todo_re_check_options_route_in_fractal_action/mysql/modules/api/v2/controllers/base/CommentController.php b/tests/specs/issue_fix/35_resolve_todo_re_check_options_route_in_fractal_action/mysql/modules/api/v2/controllers/base/CommentController.php index f567c765..c173a6b2 100644 --- a/tests/specs/issue_fix/35_resolve_todo_re_check_options_route_in_fractal_action/mysql/modules/api/v2/controllers/base/CommentController.php +++ b/tests/specs/issue_fix/35_resolve_todo_re_check_options_route_in_fractal_action/mysql/modules/api/v2/controllers/base/CommentController.php @@ -1,8 +1,10 @@ [ - 'class' => \yii\rest\IndexAction::class, - 'modelClass' => \app\models\Pet::class, - 'checkAccess' => [$this, 'checkAccess'], - ], - 'create' => [ - 'class' => \yii\rest\CreateAction::class, - 'modelClass' => \app\models\Pet::class, + 'class' => \insolita\fractal\actions\ListAction::class, 'checkAccess' => [$this, 'checkAccess'], - ], - 'view' => [ - 'class' => \yii\rest\ViewAction::class, + 'transformer' => \app\transformers\PetTransformer::class, 'modelClass' => \app\models\Pet::class, - 'checkAccess' => [$this, 'checkAccess'], + 'resourceKey' => 'pets', + 'dataFilter' => null, + 'prepareDataProvider' => null ], - 'delete' => [ - 'class' => \yii\rest\DeleteAction::class, - 'modelClass' => \app\models\Pet::class, + 'create' => [ + 'class' => \insolita\fractal\actions\CreateAction::class, 'checkAccess' => [$this, 'checkAccess'], - ], - 'update' => [ - 'class' => \yii\rest\UpdateAction::class, + 'transformer' => \app\transformers\PetTransformer::class, 'modelClass' => \app\models\Pet::class, - 'checkAccess' => [$this, 'checkAccess'], + 'resourceKey' => 'pets', + 'allowedRelations'=>[], + 'viewRoute' => 'view', + 'scenario' => 'default' ], 'options' => [ 'class' => \yii\rest\OptionsAction::class, @@ -51,5 +47,4 @@ public function actions() * @throws \yii\web\ForbiddenHttpException if the user does not have access */ abstract public function checkAccess($action, $model = null, $params = []); - } diff --git a/tests/specs/issue_fix/35_resolve_todo_re_check_options_route_in_fractal_action/mysql/transformers/PetTransformer.php b/tests/specs/issue_fix/35_resolve_todo_re_check_options_route_in_fractal_action/mysql/transformers/PetTransformer.php new file mode 100644 index 00000000..997cd425 --- /dev/null +++ b/tests/specs/issue_fix/35_resolve_todo_re_check_options_route_in_fractal_action/mysql/transformers/PetTransformer.php @@ -0,0 +1,10 @@ +getAttributes(); + } + + public function includeStore(Pet $model) + { + $relation = $model->store; + if ($relation === null) { + return $this->null(); + } + $transformer = new StoreTransformer(); + return $this->item($relation, $transformer, 'stores'); + } +} diff --git a/tests/specs/issue_fix/35_resolve_todo_re_check_options_route_in_fractal_action/mysql/transformers/base/StoreTransformer.php b/tests/specs/issue_fix/35_resolve_todo_re_check_options_route_in_fractal_action/mysql/transformers/base/StoreTransformer.php new file mode 100644 index 00000000..7bca97a8 --- /dev/null +++ b/tests/specs/issue_fix/35_resolve_todo_re_check_options_route_in_fractal_action/mysql/transformers/base/StoreTransformer.php @@ -0,0 +1,16 @@ +getAttributes(); + } +} diff --git a/tests/specs/issue_fix/35_resolve_todo_re_check_options_route_in_rest_action/mysql/config/urls.rest.php b/tests/specs/issue_fix/35_resolve_todo_re_check_options_route_in_rest_action/mysql/config/urls.rest.php new file mode 100644 index 00000000..14a0ef55 --- /dev/null +++ b/tests/specs/issue_fix/35_resolve_todo_re_check_options_route_in_rest_action/mysql/config/urls.rest.php @@ -0,0 +1,25 @@ + 'some/pet/list', + 'POST api/v1/pets' => 'some/pet/create', + 'GET animals/pets/' => 'pet/view', + 'DELETE animals/pets/' => 'pet/delete', + 'PATCH animals/pets/' => 'pet/update', + 'GET petComments' => 'pet-comment/list', + 'GET info/pet-details' => 'petinfo/pet-detail/list', + 'GET forum/pet2-details' => 'forum/pet2-detail/list', + 'GET forum2/pet3-details' => 'forum2/pet3-detail/list', + 'GET api/v2/comments' => 'api/v2/comment/list', + 'api/v1/pets' => 'some/pet/options', + 'animals/pets/' => 'pet/options', + 'petComments' => 'pet-comment/options', + 'info/pet-details' => 'petinfo/pet-detail/options', + 'forum/pet2-details' => 'forum/pet2-detail/options', + 'forum2/pet3-details' => 'forum2/pet3-detail/options', + 'api/v2/comments' => 'api/v2/comment/options', +]; diff --git a/tests/specs/issue_fix/35_resolve_todo_re_check_options_route_in_rest_action/mysql/controllers/PetCommentController.php b/tests/specs/issue_fix/35_resolve_todo_re_check_options_route_in_rest_action/mysql/controllers/PetCommentController.php new file mode 100644 index 00000000..b71a5cb0 --- /dev/null +++ b/tests/specs/issue_fix/35_resolve_todo_re_check_options_route_in_rest_action/mysql/controllers/PetCommentController.php @@ -0,0 +1,20 @@ + [ + 'class' => \yii\rest\OptionsAction::class, + ], + ]; + } + + /** + * Checks the privilege of the current user. + * + * This method checks whether the current user has the privilege + * to run the specified action against the specified data model. + * If the user does not have access, a [[ForbiddenHttpException]] should be thrown. + * + * @param string $action the ID of the action to be executed + * @param object $model the model to be accessed. If null, it means no specific model is being accessed. + * @param array $params additional parameters + * @throws \yii\web\ForbiddenHttpException if the user does not have access + */ + abstract public function checkAccess($action, $model = null, $params = []); + + abstract public function actionList(); + +} diff --git a/tests/specs/issue_fix/35_resolve_todo_re_check_options_route_in_rest_action/mysql/controllers/base/PetController.php b/tests/specs/issue_fix/35_resolve_todo_re_check_options_route_in_rest_action/mysql/controllers/base/PetController.php new file mode 100644 index 00000000..9f6daa3e --- /dev/null +++ b/tests/specs/issue_fix/35_resolve_todo_re_check_options_route_in_rest_action/mysql/controllers/base/PetController.php @@ -0,0 +1,45 @@ + [ + 'class' => \yii\rest\ViewAction::class, + 'modelClass' => \app\models\Pet::class, + 'checkAccess' => [$this, 'checkAccess'], + ], + 'delete' => [ + 'class' => \yii\rest\DeleteAction::class, + 'modelClass' => \app\models\Pet::class, + 'checkAccess' => [$this, 'checkAccess'], + ], + 'update' => [ + 'class' => \yii\rest\UpdateAction::class, + 'modelClass' => \app\models\Pet::class, + 'checkAccess' => [$this, 'checkAccess'], + ], + 'options' => [ + 'class' => \yii\rest\OptionsAction::class, + ], + ]; + } + + /** + * Checks the privilege of the current user. + * + * This method checks whether the current user has the privilege + * to run the specified action against the specified data model. + * If the user does not have access, a [[ForbiddenHttpException]] should be thrown. + * + * @param string $action the ID of the action to be executed + * @param object $model the model to be accessed. If null, it means no specific model is being accessed. + * @param array $params additional parameters + * @throws \yii\web\ForbiddenHttpException if the user does not have access + */ + abstract public function checkAccess($action, $model = null, $params = []); + +} diff --git a/tests/specs/issue_fix/35_resolve_todo_re_check_options_route_in_rest_action/mysql/modules/api/v2/controllers/CommentController.php b/tests/specs/issue_fix/35_resolve_todo_re_check_options_route_in_rest_action/mysql/modules/api/v2/controllers/CommentController.php new file mode 100644 index 00000000..55b0bc54 --- /dev/null +++ b/tests/specs/issue_fix/35_resolve_todo_re_check_options_route_in_rest_action/mysql/modules/api/v2/controllers/CommentController.php @@ -0,0 +1,20 @@ + [ + 'class' => \yii\rest\OptionsAction::class, + ], + ]; + } + + /** + * Checks the privilege of the current user. + * + * This method checks whether the current user has the privilege + * to run the specified action against the specified data model. + * If the user does not have access, a [[ForbiddenHttpException]] should be thrown. + * + * @param string $action the ID of the action to be executed + * @param object $model the model to be accessed. If null, it means no specific model is being accessed. + * @param array $params additional parameters + * @throws \yii\web\ForbiddenHttpException if the user does not have access + */ + abstract public function checkAccess($action, $model = null, $params = []); + + abstract public function actionList(); + +} diff --git a/tests/specs/issue_fix/35_resolve_todo_re_check_options_route_in_rest_action/mysql/modules/forum/controllers/Pet2DetailController.php b/tests/specs/issue_fix/35_resolve_todo_re_check_options_route_in_rest_action/mysql/modules/forum/controllers/Pet2DetailController.php new file mode 100644 index 00000000..550fa36d --- /dev/null +++ b/tests/specs/issue_fix/35_resolve_todo_re_check_options_route_in_rest_action/mysql/modules/forum/controllers/Pet2DetailController.php @@ -0,0 +1,20 @@ + [ + 'class' => \yii\rest\OptionsAction::class, + ], + ]; + } + + /** + * Checks the privilege of the current user. + * + * This method checks whether the current user has the privilege + * to run the specified action against the specified data model. + * If the user does not have access, a [[ForbiddenHttpException]] should be thrown. + * + * @param string $action the ID of the action to be executed + * @param object $model the model to be accessed. If null, it means no specific model is being accessed. + * @param array $params additional parameters + * @throws \yii\web\ForbiddenHttpException if the user does not have access + */ + abstract public function checkAccess($action, $model = null, $params = []); + + abstract public function actionList(); + +} diff --git a/tests/specs/issue_fix/35_resolve_todo_re_check_options_route_in_rest_action/mysql/modules/forum2/controllers/Pet3DetailController.php b/tests/specs/issue_fix/35_resolve_todo_re_check_options_route_in_rest_action/mysql/modules/forum2/controllers/Pet3DetailController.php new file mode 100644 index 00000000..9fbebaf9 --- /dev/null +++ b/tests/specs/issue_fix/35_resolve_todo_re_check_options_route_in_rest_action/mysql/modules/forum2/controllers/Pet3DetailController.php @@ -0,0 +1,20 @@ + [ + 'class' => \yii\rest\OptionsAction::class, + ], + ]; + } + + /** + * Checks the privilege of the current user. + * + * This method checks whether the current user has the privilege + * to run the specified action against the specified data model. + * If the user does not have access, a [[ForbiddenHttpException]] should be thrown. + * + * @param string $action the ID of the action to be executed + * @param object $model the model to be accessed. If null, it means no specific model is being accessed. + * @param array $params additional parameters + * @throws \yii\web\ForbiddenHttpException if the user does not have access + */ + abstract public function checkAccess($action, $model = null, $params = []); + + abstract public function actionList(); + +} diff --git a/tests/specs/issue_fix/35_resolve_todo_re_check_options_route_in_rest_action/mysql/modules/petinfo/Module.php b/tests/specs/issue_fix/35_resolve_todo_re_check_options_route_in_rest_action/mysql/modules/petinfo/Module.php new file mode 100644 index 00000000..de8f770b --- /dev/null +++ b/tests/specs/issue_fix/35_resolve_todo_re_check_options_route_in_rest_action/mysql/modules/petinfo/Module.php @@ -0,0 +1,15 @@ + [ + 'class' => \yii\rest\OptionsAction::class, + ], + ]; + } + + /** + * Checks the privilege of the current user. + * + * This method checks whether the current user has the privilege + * to run the specified action against the specified data model. + * If the user does not have access, a [[ForbiddenHttpException]] should be thrown. + * + * @param string $action the ID of the action to be executed + * @param object $model the model to be accessed. If null, it means no specific model is being accessed. + * @param array $params additional parameters + * @throws \yii\web\ForbiddenHttpException if the user does not have access + */ + abstract public function checkAccess($action, $model = null, $params = []); + + abstract public function actionList(); + +} diff --git a/tests/specs/issue_fix/35_resolve_todo_re_check_options_route_in_rest_action/mysql/modules/some/controllers/PetController.php b/tests/specs/issue_fix/35_resolve_todo_re_check_options_route_in_rest_action/mysql/modules/some/controllers/PetController.php new file mode 100644 index 00000000..729402bc --- /dev/null +++ b/tests/specs/issue_fix/35_resolve_todo_re_check_options_route_in_rest_action/mysql/modules/some/controllers/PetController.php @@ -0,0 +1,15 @@ + [ + 'class' => \yii\rest\IndexAction::class, + 'modelClass' => \app\models\Pet::class, + 'checkAccess' => [$this, 'checkAccess'], + ], + 'create' => [ + 'class' => \yii\rest\CreateAction::class, + 'modelClass' => \app\models\Pet::class, + 'checkAccess' => [$this, 'checkAccess'], + ], + 'options' => [ + 'class' => \yii\rest\OptionsAction::class, + ], + ]; + } + + /** + * Checks the privilege of the current user. + * + * This method checks whether the current user has the privilege + * to run the specified action against the specified data model. + * If the user does not have access, a [[ForbiddenHttpException]] should be thrown. + * + * @param string $action the ID of the action to be executed + * @param object $model the model to be accessed. If null, it means no specific model is being accessed. + * @param array $params additional parameters + * @throws \yii\web\ForbiddenHttpException if the user does not have access + */ + abstract public function checkAccess($action, $model = null, $params = []); + +} diff --git a/tests/specs/issue_fix/controller_namespace_issue_for_modules_in_urlprefixes/index.php b/tests/specs/issue_fix/controller_namespace_issue_for_modules_in_urlprefixes/index.php new file mode 100644 index 00000000..5ec71d20 --- /dev/null +++ b/tests/specs/issue_fix/controller_namespace_issue_for_modules_in_urlprefixes/index.php @@ -0,0 +1,21 @@ + '@specs/issue_fix/controller_namespace_issue_for_modules_in_urlprefixes/index.yaml', + 'generateUrls' => true, + 'generateModels' => false, + 'excludeModels' => [ + 'Error', + ], + 'generateControllers' => true, + 'generateMigrations' => false, + 'useJsonApi' => true, + 'urlPrefixes' => [ + 'animals' => '', + '/info' => ['module' =>'petinfo','namespace' => '\app\modules\petinfo\controllers'], + '/fgh' => ['namespace' => '\app\modules\fgh\controllers'], + '/fgh2' => ['path' => '@app/modules/fgh2/controllers', 'namespace' => '\app\fgh2\controllers'], + '/api/v1' => ['path' => '@app/modules/api/v1/controllers', 'namespace' => '\app\api\v1\controllers'], + 'theprefix' => ['module' => 'themodule', 'namespace' => '\app\modules\themodule\controllers'] + ] +]; diff --git a/tests/specs/issue_fix/controller_namespace_issue_for_modules_in_urlprefixes/index.yaml b/tests/specs/issue_fix/controller_namespace_issue_for_modules_in_urlprefixes/index.yaml new file mode 100644 index 00000000..b22d58b6 --- /dev/null +++ b/tests/specs/issue_fix/controller_namespace_issue_for_modules_in_urlprefixes/index.yaml @@ -0,0 +1,178 @@ +openapi: "3.0.0" +info: + version: 1.0.0 + title: controller_namespace_issue_for_modules_in_urlprefixes + license: + name: MIT +servers: + - url: http://petstore.swagger.io/v1 +paths: + /api/v1/pets: + get: + summary: List all pets + operationId: listPets + tags: + - pets + parameters: + - name: limit + in: query + description: How many items to return at one time (max 100) + required: false + schema: + type: integer + format: int32 + responses: + '200': + description: A paged array of pets + headers: + x-next: + description: A link to the next page of responses + schema: + type: string + content: + application/json: + schema: + $ref: "#/components/schemas/Pets" + default: + description: unexpected error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + post: + summary: Create a pet + operationId: createPets + tags: + - pets + responses: + '201': + description: Null response + default: + description: unexpected error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + /animals/pets/{id}: + parameters: + - name: id + in: path + required: true + description: The id of the pet to update + schema: + type: string + get: + summary: Info for a specific pet + operationId: showPetById + tags: + - pets + responses: + '200': + description: Expected response to a valid request + content: + application/json: + schema: + $ref: "#/components/schemas/Pet" + default: + description: unexpected error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + patch: + summary: update a specific pet + operationId: updatePetById + tags: + - pets + responses: + '200': + description: The updated pet + content: + application/json: + schema: + $ref: "#/components/schemas/Pet" + delete: + summary: delete a specific pet + operationId: deletePetById + tags: + - pets + responses: + '204': + description: successfully deleted pet + /petComments: + get: + description: list all pet comments + responses: + '200': + description: list of comments + /info/pet-details: + get: + description: list all pet details + responses: + '200': + description: list of details + /fgh/pet-detail2s: + get: +# x-route: f/l789898 + description: list all pet details + responses: + '200': + description: list of details + /fgh2/pet-detail2s: + get: + description: list all pet details + responses: + '200': + description: list of details + /theprefix/ctrl: + get: + description: list all pet details + responses: + '200': + description: list of details + +components: + schemas: + Pet: + description: A Pet + required: + - id + - name + properties: + id: + type: integer + format: int64 + readOnly: True + name: + type: string + store: + $ref: '#/components/schemas/Store' + tag: + type: string + x-faker: "$faker->randomElement(['one', 'two', 'three', 'four'])" + Store: + description: A store's description + required: + - id + - name + properties: + id: + type: integer + format: int64 + readOnly: True + name: + type: string + Pets: + type: array + items: + $ref: "#/components/schemas/Pet" + Error: + required: + - code + - message + properties: + code: + type: integer + format: int32 + message: + type: string diff --git a/tests/specs/issue_fix/controller_namespace_issue_for_modules_in_urlprefixes/mysql/config/urls.rest.php b/tests/specs/issue_fix/controller_namespace_issue_for_modules_in_urlprefixes/mysql/config/urls.rest.php new file mode 100644 index 00000000..94f27681 --- /dev/null +++ b/tests/specs/issue_fix/controller_namespace_issue_for_modules_in_urlprefixes/mysql/config/urls.rest.php @@ -0,0 +1,25 @@ + 'api/v1/pet/list', + 'POST api/v1/pets' => 'api/v1/pet/create', + 'GET animals/pets/' => 'pet/view', + 'DELETE animals/pets/' => 'pet/delete', + 'PATCH animals/pets/' => 'pet/update', + 'GET petComments' => 'pet-comment/list', + 'GET info/pet-details' => 'petinfo/pet-detail/list', + 'GET fgh/pet-detail2s' => 'fgh/pet-detail2/list', + 'GET fgh2/pet-detail2s' => 'fgh2/pet-detail2/list', + 'GET theprefix/ctrl' => 'themodule/ctrl/list', + 'api/v1/pets' => 'api/v1/pet/options', + 'animals/pets/' => 'pet/options', + 'petComments' => 'pet-comment/options', + 'info/pet-details' => 'petinfo/pet-detail/options', + 'fgh/pet-detail2s' => 'fgh/pet-detail2/options', + 'fgh2/pet-detail2s' => 'fgh2/pet-detail2/options', + 'theprefix/ctrl' => 'themodule/ctrl/options', +]; diff --git a/tests/specs/issue_fix/controller_namespace_issue_for_modules_in_urlprefixes/mysql/controllers/PetCommentController.php b/tests/specs/issue_fix/controller_namespace_issue_for_modules_in_urlprefixes/mysql/controllers/PetCommentController.php new file mode 100644 index 00000000..560e0858 --- /dev/null +++ b/tests/specs/issue_fix/controller_namespace_issue_for_modules_in_urlprefixes/mysql/controllers/PetCommentController.php @@ -0,0 +1,26 @@ + [ + 'class' => \yii\rest\OptionsAction::class, + ], + ]; + } + + /** + * Checks the privilege of the current user. + * + * This method checks whether the current user has the privilege + * to run the specified action against the specified data model. + * If the user does not have access, a [[ForbiddenHttpException]] should be thrown. + * + * @param string $action the ID of the action to be executed + * @param object $model the model to be accessed. If null, it means no specific model is being accessed. + * @param array $params additional parameters + * @throws \yii\web\ForbiddenHttpException if the user does not have access + */ + abstract public function checkAccess($action, $model = null, $params = []); + + abstract public function actionList(); +} diff --git a/tests/specs/issue_fix/controller_namespace_issue_for_modules_in_urlprefixes/mysql/controllers/base/PetController.php b/tests/specs/issue_fix/controller_namespace_issue_for_modules_in_urlprefixes/mysql/controllers/base/PetController.php new file mode 100644 index 00000000..a3f18f81 --- /dev/null +++ b/tests/specs/issue_fix/controller_namespace_issue_for_modules_in_urlprefixes/mysql/controllers/base/PetController.php @@ -0,0 +1,55 @@ + [ + 'class' => \insolita\fractal\actions\ViewAction::class, + 'checkAccess' => [$this, 'checkAccess'], + 'transformer' => \app\transformers\PetTransformer::class, + 'modelClass' => \app\models\Pet::class, + 'resourceKey' => 'pets', + 'findModel' => null + ], + 'delete' => [ + 'class' => \insolita\fractal\actions\DeleteAction::class, + 'checkAccess' => [$this, 'checkAccess'], + 'modelClass' => \app\models\Pet::class, + 'findModel' => null + ], + 'update' => [ + 'class' => \insolita\fractal\actions\UpdateAction::class, + 'checkAccess' => [$this, 'checkAccess'], + 'transformer' => \app\transformers\PetTransformer::class, + 'modelClass' => \app\models\Pet::class, + 'resourceKey' => 'pets', + 'findModel' => null, + 'allowedRelations'=>[], + 'scenario' => 'default' + ], + 'options' => [ + 'class' => \yii\rest\OptionsAction::class, + ], + ]; + } + + /** + * Checks the privilege of the current user. + * + * This method checks whether the current user has the privilege + * to run the specified action against the specified data model. + * If the user does not have access, a [[ForbiddenHttpException]] should be thrown. + * + * @param string $action the ID of the action to be executed + * @param object $model the model to be accessed. If null, it means no specific model is being accessed. + * @param array $params additional parameters + * @throws \yii\web\ForbiddenHttpException if the user does not have access + */ + abstract public function checkAccess($action, $model = null, $params = []); +} diff --git a/tests/specs/issue_fix/controller_namespace_issue_for_modules_in_urlprefixes/mysql/modules/api/v1/controllers/PetController.php b/tests/specs/issue_fix/controller_namespace_issue_for_modules_in_urlprefixes/mysql/modules/api/v1/controllers/PetController.php new file mode 100644 index 00000000..5bd26301 --- /dev/null +++ b/tests/specs/issue_fix/controller_namespace_issue_for_modules_in_urlprefixes/mysql/modules/api/v1/controllers/PetController.php @@ -0,0 +1,21 @@ + [ + 'class' => \insolita\fractal\actions\ListAction::class, + 'checkAccess' => [$this, 'checkAccess'], + 'transformer' => \app\transformers\PetTransformer::class, + 'modelClass' => \app\models\Pet::class, + 'resourceKey' => 'pets', + 'dataFilter' => null, + 'prepareDataProvider' => null + ], + 'create' => [ + 'class' => \insolita\fractal\actions\CreateAction::class, + 'checkAccess' => [$this, 'checkAccess'], + 'transformer' => \app\transformers\PetTransformer::class, + 'modelClass' => \app\models\Pet::class, + 'resourceKey' => 'pets', + 'allowedRelations'=>[], + 'viewRoute' => 'view', + 'scenario' => 'default' + ], + 'options' => [ + 'class' => \yii\rest\OptionsAction::class, + ], + ]; + } + + /** + * Checks the privilege of the current user. + * + * This method checks whether the current user has the privilege + * to run the specified action against the specified data model. + * If the user does not have access, a [[ForbiddenHttpException]] should be thrown. + * + * @param string $action the ID of the action to be executed + * @param object $model the model to be accessed. If null, it means no specific model is being accessed. + * @param array $params additional parameters + * @throws \yii\web\ForbiddenHttpException if the user does not have access + */ + abstract public function checkAccess($action, $model = null, $params = []); +} diff --git a/tests/specs/issue_fix/controller_namespace_issue_for_modules_in_urlprefixes/mysql/modules/fgh/controllers/PetDetail2Controller.php b/tests/specs/issue_fix/controller_namespace_issue_for_modules_in_urlprefixes/mysql/modules/fgh/controllers/PetDetail2Controller.php new file mode 100644 index 00000000..814839e4 --- /dev/null +++ b/tests/specs/issue_fix/controller_namespace_issue_for_modules_in_urlprefixes/mysql/modules/fgh/controllers/PetDetail2Controller.php @@ -0,0 +1,26 @@ + [ + 'class' => \yii\rest\OptionsAction::class, + ], + ]; + } + + /** + * Checks the privilege of the current user. + * + * This method checks whether the current user has the privilege + * to run the specified action against the specified data model. + * If the user does not have access, a [[ForbiddenHttpException]] should be thrown. + * + * @param string $action the ID of the action to be executed + * @param object $model the model to be accessed. If null, it means no specific model is being accessed. + * @param array $params additional parameters + * @throws \yii\web\ForbiddenHttpException if the user does not have access + */ + abstract public function checkAccess($action, $model = null, $params = []); + + abstract public function actionList(); +} diff --git a/tests/specs/issue_fix/controller_namespace_issue_for_modules_in_urlprefixes/mysql/modules/fgh2/controllers/PetDetail2Controller.php b/tests/specs/issue_fix/controller_namespace_issue_for_modules_in_urlprefixes/mysql/modules/fgh2/controllers/PetDetail2Controller.php new file mode 100644 index 00000000..f0c8593b --- /dev/null +++ b/tests/specs/issue_fix/controller_namespace_issue_for_modules_in_urlprefixes/mysql/modules/fgh2/controllers/PetDetail2Controller.php @@ -0,0 +1,26 @@ + [ + 'class' => \yii\rest\OptionsAction::class, + ], + ]; + } + + /** + * Checks the privilege of the current user. + * + * This method checks whether the current user has the privilege + * to run the specified action against the specified data model. + * If the user does not have access, a [[ForbiddenHttpException]] should be thrown. + * + * @param string $action the ID of the action to be executed + * @param object $model the model to be accessed. If null, it means no specific model is being accessed. + * @param array $params additional parameters + * @throws \yii\web\ForbiddenHttpException if the user does not have access + */ + abstract public function checkAccess($action, $model = null, $params = []); + + abstract public function actionList(); +} diff --git a/tests/specs/issue_fix/controller_namespace_issue_for_modules_in_urlprefixes/mysql/modules/petinfo/Module.php b/tests/specs/issue_fix/controller_namespace_issue_for_modules_in_urlprefixes/mysql/modules/petinfo/Module.php new file mode 100644 index 00000000..de8f770b --- /dev/null +++ b/tests/specs/issue_fix/controller_namespace_issue_for_modules_in_urlprefixes/mysql/modules/petinfo/Module.php @@ -0,0 +1,15 @@ + [ + 'class' => \yii\rest\OptionsAction::class, + ], + ]; + } + + /** + * Checks the privilege of the current user. + * + * This method checks whether the current user has the privilege + * to run the specified action against the specified data model. + * If the user does not have access, a [[ForbiddenHttpException]] should be thrown. + * + * @param string $action the ID of the action to be executed + * @param object $model the model to be accessed. If null, it means no specific model is being accessed. + * @param array $params additional parameters + * @throws \yii\web\ForbiddenHttpException if the user does not have access + */ + abstract public function checkAccess($action, $model = null, $params = []); + + abstract public function actionList(); +} diff --git a/tests/specs/issue_fix/controller_namespace_issue_for_modules_in_urlprefixes/mysql/modules/themodule/Module.php b/tests/specs/issue_fix/controller_namespace_issue_for_modules_in_urlprefixes/mysql/modules/themodule/Module.php new file mode 100644 index 00000000..d6797d06 --- /dev/null +++ b/tests/specs/issue_fix/controller_namespace_issue_for_modules_in_urlprefixes/mysql/modules/themodule/Module.php @@ -0,0 +1,15 @@ + [ + 'class' => \yii\rest\OptionsAction::class, + ], + ]; + } + + /** + * Checks the privilege of the current user. + * + * This method checks whether the current user has the privilege + * to run the specified action against the specified data model. + * If the user does not have access, a [[ForbiddenHttpException]] should be thrown. + * + * @param string $action the ID of the action to be executed + * @param object $model the model to be accessed. If null, it means no specific model is being accessed. + * @param array $params additional parameters + * @throws \yii\web\ForbiddenHttpException if the user does not have access + */ + abstract public function checkAccess($action, $model = null, $params = []); + + abstract public function actionList(); +} diff --git a/tests/specs/issue_fix/controller_namespace_issue_for_modules_in_urlprefixes/mysql/transformers/PetTransformer.php b/tests/specs/issue_fix/controller_namespace_issue_for_modules_in_urlprefixes/mysql/transformers/PetTransformer.php new file mode 100644 index 00000000..997cd425 --- /dev/null +++ b/tests/specs/issue_fix/controller_namespace_issue_for_modules_in_urlprefixes/mysql/transformers/PetTransformer.php @@ -0,0 +1,10 @@ +getAttributes(); + } + + public function includeStore(Pet $model) + { + $relation = $model->store; + if ($relation === null) { + return $this->null(); + } + $transformer = new StoreTransformer(); + return $this->item($relation, $transformer, 'stores'); + } +} diff --git a/tests/specs/issue_fix/controller_namespace_issue_for_modules_in_urlprefixes/mysql/transformers/base/StoreTransformer.php b/tests/specs/issue_fix/controller_namespace_issue_for_modules_in_urlprefixes/mysql/transformers/base/StoreTransformer.php new file mode 100644 index 00000000..7bca97a8 --- /dev/null +++ b/tests/specs/issue_fix/controller_namespace_issue_for_modules_in_urlprefixes/mysql/transformers/base/StoreTransformer.php @@ -0,0 +1,16 @@ +getAttributes(); + } +} diff --git a/tests/specs/issue_fix/controller_namespace_issue_for_modules_in_urlprefixes/rest/config/urls.rest.php b/tests/specs/issue_fix/controller_namespace_issue_for_modules_in_urlprefixes/rest/config/urls.rest.php new file mode 100644 index 00000000..94f27681 --- /dev/null +++ b/tests/specs/issue_fix/controller_namespace_issue_for_modules_in_urlprefixes/rest/config/urls.rest.php @@ -0,0 +1,25 @@ + 'api/v1/pet/list', + 'POST api/v1/pets' => 'api/v1/pet/create', + 'GET animals/pets/' => 'pet/view', + 'DELETE animals/pets/' => 'pet/delete', + 'PATCH animals/pets/' => 'pet/update', + 'GET petComments' => 'pet-comment/list', + 'GET info/pet-details' => 'petinfo/pet-detail/list', + 'GET fgh/pet-detail2s' => 'fgh/pet-detail2/list', + 'GET fgh2/pet-detail2s' => 'fgh2/pet-detail2/list', + 'GET theprefix/ctrl' => 'themodule/ctrl/list', + 'api/v1/pets' => 'api/v1/pet/options', + 'animals/pets/' => 'pet/options', + 'petComments' => 'pet-comment/options', + 'info/pet-details' => 'petinfo/pet-detail/options', + 'fgh/pet-detail2s' => 'fgh/pet-detail2/options', + 'fgh2/pet-detail2s' => 'fgh2/pet-detail2/options', + 'theprefix/ctrl' => 'themodule/ctrl/options', +]; diff --git a/tests/specs/issue_fix/controller_namespace_issue_for_modules_in_urlprefixes/rest/controllers/PetCommentController.php b/tests/specs/issue_fix/controller_namespace_issue_for_modules_in_urlprefixes/rest/controllers/PetCommentController.php new file mode 100644 index 00000000..b71a5cb0 --- /dev/null +++ b/tests/specs/issue_fix/controller_namespace_issue_for_modules_in_urlprefixes/rest/controllers/PetCommentController.php @@ -0,0 +1,20 @@ + [ + 'class' => \yii\rest\OptionsAction::class, + ], + ]; + } + + /** + * Checks the privilege of the current user. + * + * This method checks whether the current user has the privilege + * to run the specified action against the specified data model. + * If the user does not have access, a [[ForbiddenHttpException]] should be thrown. + * + * @param string $action the ID of the action to be executed + * @param object $model the model to be accessed. If null, it means no specific model is being accessed. + * @param array $params additional parameters + * @throws \yii\web\ForbiddenHttpException if the user does not have access + */ + abstract public function checkAccess($action, $model = null, $params = []); + + abstract public function actionList(); + +} diff --git a/tests/specs/issue_fix/controller_namespace_issue_for_modules_in_urlprefixes/rest/controllers/base/PetController.php b/tests/specs/issue_fix/controller_namespace_issue_for_modules_in_urlprefixes/rest/controllers/base/PetController.php new file mode 100644 index 00000000..9f6daa3e --- /dev/null +++ b/tests/specs/issue_fix/controller_namespace_issue_for_modules_in_urlprefixes/rest/controllers/base/PetController.php @@ -0,0 +1,45 @@ + [ + 'class' => \yii\rest\ViewAction::class, + 'modelClass' => \app\models\Pet::class, + 'checkAccess' => [$this, 'checkAccess'], + ], + 'delete' => [ + 'class' => \yii\rest\DeleteAction::class, + 'modelClass' => \app\models\Pet::class, + 'checkAccess' => [$this, 'checkAccess'], + ], + 'update' => [ + 'class' => \yii\rest\UpdateAction::class, + 'modelClass' => \app\models\Pet::class, + 'checkAccess' => [$this, 'checkAccess'], + ], + 'options' => [ + 'class' => \yii\rest\OptionsAction::class, + ], + ]; + } + + /** + * Checks the privilege of the current user. + * + * This method checks whether the current user has the privilege + * to run the specified action against the specified data model. + * If the user does not have access, a [[ForbiddenHttpException]] should be thrown. + * + * @param string $action the ID of the action to be executed + * @param object $model the model to be accessed. If null, it means no specific model is being accessed. + * @param array $params additional parameters + * @throws \yii\web\ForbiddenHttpException if the user does not have access + */ + abstract public function checkAccess($action, $model = null, $params = []); + +} diff --git a/tests/specs/issue_fix/controller_namespace_issue_for_modules_in_urlprefixes/rest/modules/api/v1/controllers/PetController.php b/tests/specs/issue_fix/controller_namespace_issue_for_modules_in_urlprefixes/rest/modules/api/v1/controllers/PetController.php new file mode 100644 index 00000000..729402bc --- /dev/null +++ b/tests/specs/issue_fix/controller_namespace_issue_for_modules_in_urlprefixes/rest/modules/api/v1/controllers/PetController.php @@ -0,0 +1,15 @@ + [ + 'class' => \yii\rest\IndexAction::class, + 'modelClass' => \app\models\Pet::class, + 'checkAccess' => [$this, 'checkAccess'], + ], + 'create' => [ + 'class' => \yii\rest\CreateAction::class, + 'modelClass' => \app\models\Pet::class, + 'checkAccess' => [$this, 'checkAccess'], + ], + 'options' => [ + 'class' => \yii\rest\OptionsAction::class, + ], + ]; + } + + /** + * Checks the privilege of the current user. + * + * This method checks whether the current user has the privilege + * to run the specified action against the specified data model. + * If the user does not have access, a [[ForbiddenHttpException]] should be thrown. + * + * @param string $action the ID of the action to be executed + * @param object $model the model to be accessed. If null, it means no specific model is being accessed. + * @param array $params additional parameters + * @throws \yii\web\ForbiddenHttpException if the user does not have access + */ + abstract public function checkAccess($action, $model = null, $params = []); + +} diff --git a/tests/specs/issue_fix/controller_namespace_issue_for_modules_in_urlprefixes/rest/modules/fgh/controllers/PetDetail2Controller.php b/tests/specs/issue_fix/controller_namespace_issue_for_modules_in_urlprefixes/rest/modules/fgh/controllers/PetDetail2Controller.php new file mode 100644 index 00000000..8ed1556c --- /dev/null +++ b/tests/specs/issue_fix/controller_namespace_issue_for_modules_in_urlprefixes/rest/modules/fgh/controllers/PetDetail2Controller.php @@ -0,0 +1,20 @@ + [ + 'class' => \yii\rest\OptionsAction::class, + ], + ]; + } + + /** + * Checks the privilege of the current user. + * + * This method checks whether the current user has the privilege + * to run the specified action against the specified data model. + * If the user does not have access, a [[ForbiddenHttpException]] should be thrown. + * + * @param string $action the ID of the action to be executed + * @param object $model the model to be accessed. If null, it means no specific model is being accessed. + * @param array $params additional parameters + * @throws \yii\web\ForbiddenHttpException if the user does not have access + */ + abstract public function checkAccess($action, $model = null, $params = []); + + abstract public function actionList(); + +} diff --git a/tests/specs/issue_fix/controller_namespace_issue_for_modules_in_urlprefixes/rest/modules/fgh2/controllers/PetDetail2Controller.php b/tests/specs/issue_fix/controller_namespace_issue_for_modules_in_urlprefixes/rest/modules/fgh2/controllers/PetDetail2Controller.php new file mode 100644 index 00000000..efc107da --- /dev/null +++ b/tests/specs/issue_fix/controller_namespace_issue_for_modules_in_urlprefixes/rest/modules/fgh2/controllers/PetDetail2Controller.php @@ -0,0 +1,20 @@ + [ + 'class' => \yii\rest\OptionsAction::class, + ], + ]; + } + + /** + * Checks the privilege of the current user. + * + * This method checks whether the current user has the privilege + * to run the specified action against the specified data model. + * If the user does not have access, a [[ForbiddenHttpException]] should be thrown. + * + * @param string $action the ID of the action to be executed + * @param object $model the model to be accessed. If null, it means no specific model is being accessed. + * @param array $params additional parameters + * @throws \yii\web\ForbiddenHttpException if the user does not have access + */ + abstract public function checkAccess($action, $model = null, $params = []); + + abstract public function actionList(); + +} diff --git a/tests/specs/issue_fix/controller_namespace_issue_for_modules_in_urlprefixes/rest/modules/petinfo/Module.php b/tests/specs/issue_fix/controller_namespace_issue_for_modules_in_urlprefixes/rest/modules/petinfo/Module.php new file mode 100644 index 00000000..de8f770b --- /dev/null +++ b/tests/specs/issue_fix/controller_namespace_issue_for_modules_in_urlprefixes/rest/modules/petinfo/Module.php @@ -0,0 +1,15 @@ + [ + 'class' => \yii\rest\OptionsAction::class, + ], + ]; + } + + /** + * Checks the privilege of the current user. + * + * This method checks whether the current user has the privilege + * to run the specified action against the specified data model. + * If the user does not have access, a [[ForbiddenHttpException]] should be thrown. + * + * @param string $action the ID of the action to be executed + * @param object $model the model to be accessed. If null, it means no specific model is being accessed. + * @param array $params additional parameters + * @throws \yii\web\ForbiddenHttpException if the user does not have access + */ + abstract public function checkAccess($action, $model = null, $params = []); + + abstract public function actionList(); + +} diff --git a/tests/specs/issue_fix/controller_namespace_issue_for_modules_in_urlprefixes/rest/modules/themodule/Module.php b/tests/specs/issue_fix/controller_namespace_issue_for_modules_in_urlprefixes/rest/modules/themodule/Module.php new file mode 100644 index 00000000..d6797d06 --- /dev/null +++ b/tests/specs/issue_fix/controller_namespace_issue_for_modules_in_urlprefixes/rest/modules/themodule/Module.php @@ -0,0 +1,15 @@ + [ + 'class' => \yii\rest\OptionsAction::class, + ], + ]; + } + + /** + * Checks the privilege of the current user. + * + * This method checks whether the current user has the privilege + * to run the specified action against the specified data model. + * If the user does not have access, a [[ForbiddenHttpException]] should be thrown. + * + * @param string $action the ID of the action to be executed + * @param object $model the model to be accessed. If null, it means no specific model is being accessed. + * @param array $params additional parameters + * @throws \yii\web\ForbiddenHttpException if the user does not have access + */ + abstract public function checkAccess($action, $model = null, $params = []); + + abstract public function actionList(); + +} diff --git a/tests/specs/petstore_urlprefixes/controllers/PetController.php b/tests/specs/petstore_urlprefixes/controllers/PetController.php new file mode 100644 index 00000000..926d8eea --- /dev/null +++ b/tests/specs/petstore_urlprefixes/controllers/PetController.php @@ -0,0 +1,15 @@ + [ + 'class' => \yii\rest\ViewAction::class, + 'modelClass' => \app\models\Pet::class, + 'checkAccess' => [$this, 'checkAccess'], + ], + 'delete' => [ + 'class' => \yii\rest\DeleteAction::class, + 'modelClass' => \app\models\Pet::class, + 'checkAccess' => [$this, 'checkAccess'], + ], + 'update' => [ + 'class' => \yii\rest\UpdateAction::class, + 'modelClass' => \app\models\Pet::class, + 'checkAccess' => [$this, 'checkAccess'], + ], + 'options' => [ + 'class' => \yii\rest\OptionsAction::class, + ], + ]; + } + + /** + * Checks the privilege of the current user. + * + * This method checks whether the current user has the privilege + * to run the specified action against the specified data model. + * If the user does not have access, a [[ForbiddenHttpException]] should be thrown. + * + * @param string $action the ID of the action to be executed + * @param object $model the model to be accessed. If null, it means no specific model is being accessed. + * @param array $params additional parameters + * @throws \yii\web\ForbiddenHttpException if the user does not have access + */ + abstract public function checkAccess($action, $model = null, $params = []); + +} diff --git a/tests/specs/petstore_urlprefixes/modules/api/v1/controllers/base/PetController.php b/tests/specs/petstore_urlprefixes/modules/api/v1/controllers/base/PetController.php index 8aef1714..29f56fe5 100644 --- a/tests/specs/petstore_urlprefixes/modules/api/v1/controllers/base/PetController.php +++ b/tests/specs/petstore_urlprefixes/modules/api/v1/controllers/base/PetController.php @@ -17,21 +17,6 @@ public function actions() 'modelClass' => \app\models\Pet::class, 'checkAccess' => [$this, 'checkAccess'], ], - 'view' => [ - 'class' => \yii\rest\ViewAction::class, - 'modelClass' => \app\models\Pet::class, - 'checkAccess' => [$this, 'checkAccess'], - ], - 'delete' => [ - 'class' => \yii\rest\DeleteAction::class, - 'modelClass' => \app\models\Pet::class, - 'checkAccess' => [$this, 'checkAccess'], - ], - 'update' => [ - 'class' => \yii\rest\UpdateAction::class, - 'modelClass' => \app\models\Pet::class, - 'checkAccess' => [$this, 'checkAccess'], - ], 'options' => [ 'class' => \yii\rest\OptionsAction::class, ], diff --git a/tests/specs/petstore_urlprefixes/modules/petinfo/Module.php b/tests/specs/petstore_urlprefixes/modules/petinfo/Module.php new file mode 100644 index 00000000..de8f770b --- /dev/null +++ b/tests/specs/petstore_urlprefixes/modules/petinfo/Module.php @@ -0,0 +1,15 @@ +checkFiles($actualFiles, $expectedFiles); } + public function testControllerNamespaceIssueForModulesInUrlPrefixes() # FractalAction + { + $testFile = Yii::getAlias("@specs/issue_fix/controller_namespace_issue_for_modules_in_urlprefixes/index.php"); + $this->runGenerator($testFile); + $actualFiles = FileHelper::findFiles(Yii::getAlias('@app'), [ + 'recursive' => true, + ]); + $expectedFiles = FileHelper::findFiles(Yii::getAlias("@specs/issue_fix/controller_namespace_issue_for_modules_in_urlprefixes/mysql"), [ + 'recursive' => true, + ]); + $this->checkFiles($actualFiles, $expectedFiles); + } + + public function testControllerNamespaceIssueForModulesInUrlPrefixesRestAction() + { + $config = []; + $config = require Yii::getAlias("@specs/issue_fix/controller_namespace_issue_for_modules_in_urlprefixes/index.php"); + $config['useJsonApi'] = false; + $tmpConfigFile = Yii::getAlias("@runtime") . "/tmp-config.php"; + file_put_contents($tmpConfigFile, 'runGenerator($tmpConfigFile); + + $actualFiles = FileHelper::findFiles(Yii::getAlias('@app'), [ + 'recursive' => true, + ]); + $expectedFiles = FileHelper::findFiles(Yii::getAlias("@specs/issue_fix/controller_namespace_issue_for_modules_in_urlprefixes/rest"), [ + 'recursive' => true, + ]); + $this->checkFiles($actualFiles, $expectedFiles); + FileHelper::unlink($tmpConfigFile); + } + // https://github.com/php-openapi/yii2-openapi/issues/60 public function test60DescriptionOfAPropertyInSpecMustCorrespondToDbTableColumnComment() { @@ -710,6 +743,7 @@ private function for60($spec, $expected) $this->assertSame($expected, $actual); $this->runActualMigrations('mysql', 1); Yii::$app->db->createCommand('DROP TABLE IF EXISTS {{%fruits}}')->execute(); + FileHelper::unlink($tmpConfigFile); } private function createTableFor60DescriptionOfAProperty() @@ -903,17 +937,21 @@ public function test35ResolveTodoReCheckOptionsRouteInFractalAction() // https://github.com/php-openapi/yii2-openapi/issues/35 public function test35ResolveTodoReCheckOptionsRouteInRestAction() { - $testFile = Yii::getAlias("@specs/issue_fix/35_resolve_todo_re_check_options_route_in_fractal_action/index.php"); - $content = str_replace("'useJsonApi' => true,", "'useJsonApi' => false,", file_get_contents($testFile)); - file_put_contents($testFile, $content); - $this->runGenerator($testFile); + $config = []; + $config = require Yii::getAlias("@specs/issue_fix/35_resolve_todo_re_check_options_route_in_fractal_action/index.php"); + $config['useJsonApi'] = false; + $tmpConfigFile = Yii::getAlias("@runtime") . "/tmp-config-35.php"; + file_put_contents($tmpConfigFile, 'runGenerator($tmpConfigFile); $actualFiles = FileHelper::findFiles(Yii::getAlias('@app'), [ 'recursive' => true, ]); - $expectedFiles = FileHelper::findFiles(Yii::getAlias("@specs/issue_fix/35_resolve_todo_re_check_options_route_in_fractal_action/mysql"), [ + $expectedFiles = FileHelper::findFiles(Yii::getAlias("@specs/issue_fix/35_resolve_todo_re_check_options_route_in_rest_action/mysql"), [ 'recursive' => true, ]); $this->checkFiles($actualFiles, $expectedFiles); + FileHelper::unlink($tmpConfigFile); } // https://github.com/php-openapi/yii2-openapi/issues/63 diff --git a/tests/unit/RestActionGeneratorTest.php b/tests/unit/RestActionGeneratorTest.php index 7fb792d6..0affc7fd 100644 --- a/tests/unit/RestActionGeneratorTest.php +++ b/tests/unit/RestActionGeneratorTest.php @@ -106,6 +106,7 @@ public function dataProvider():array 'prefix' => '', 'prefixSettings' => [], 'responseWrapper' => ['item' => '', 'list' => '', 'type' => 'array'], + 'xRoute' => null, ]), new RestAction([ 'id' => 'view', @@ -118,6 +119,7 @@ public function dataProvider():array 'modelName' => 'Post', 'modelFqn' => 'app\models\Post', 'responseWrapper' => ['item' => 'post', 'list' => null, 'type' => 'object'], + 'xRoute' => null, ]), new RestAction([ 'id' => 'view-related-category', @@ -132,6 +134,7 @@ public function dataProvider():array 'modelName' => 'Post', 'modelFqn' => 'app\models\Post', 'responseWrapper' => ['item' => 'category', 'list' => null, 'type' => 'object'], + 'xRoute' => null, ]), new RestAction([ 'id' => 'list-related-comments', @@ -146,6 +149,7 @@ public function dataProvider():array 'modelName' => 'Post', 'modelFqn' => 'app\models\Post', 'responseWrapper' => ['item' => '', 'list' => '', 'type' => 'array'], + 'xRoute' => null, ]), new RestAction([ 'id' => 'list-for-post', @@ -160,6 +164,7 @@ public function dataProvider():array 'modelName' => 'Comment', 'modelFqn' => 'app\models\Comment', 'responseWrapper' => ['item' => '', 'list' => '', 'type' => 'array'], + 'xRoute' => null, ]), new RestAction([ 'id' => 'create-for-post', @@ -174,6 +179,7 @@ public function dataProvider():array 'modelName' => 'Comment', 'modelFqn' => 'app\models\Comment', 'responseWrapper' => null, + 'xRoute' => null, ]), new RestAction([ 'id' => 'view-for-category', @@ -189,6 +195,7 @@ public function dataProvider():array 'modelName' => 'Post', 'modelFqn' => 'app\models\Post', 'responseWrapper' => ['item' => '', 'list' => '', 'type' => 'object'], + 'xRoute' => null, ]), new RestAction([ 'id' => 'view-for-post', @@ -204,6 +211,7 @@ public function dataProvider():array 'modelName' => 'Comment', 'modelFqn' => 'app\models\Comment', 'responseWrapper' => ['item' => '', 'list' => '', 'type' => 'object'], + 'xRoute' => null, ]), new RestAction([ 'id' => 'delete-for-post', @@ -219,6 +227,7 @@ public function dataProvider():array 'modelName' => 'Comment', 'modelFqn' => 'app\models\Comment', 'responseWrapper' => null, + 'xRoute' => null, ]), new RestAction([ 'id' => 'update-for-post', @@ -234,6 +243,7 @@ public function dataProvider():array 'modelName' => 'Comment', 'modelFqn' => 'app\models\Comment', 'responseWrapper' => ['item' => '', 'list' => '', 'type' => 'object'], + 'xRoute' => null, ]), ], ], @@ -252,6 +262,7 @@ public function dataProvider():array 'modelName' => 'Pet', 'modelFqn' => 'app\mymodels\Pet', 'responseWrapper' => ['item' => '', 'list' => '', 'type' => 'array'], + 'xRoute' => null, ]), new RestAction([ 'id' => 'create', @@ -264,6 +275,7 @@ public function dataProvider():array 'modelName' => 'Pet', 'modelFqn' => 'app\mymodels\Pet', 'responseWrapper' => null, + 'xRoute' => null, ]), new RestAction([ 'id' => 'view', @@ -276,6 +288,7 @@ public function dataProvider():array 'modelName' => 'Pet', 'modelFqn' => 'app\mymodels\Pet', 'responseWrapper' => ['item' => '', 'list' => '', 'type' => 'object'], + 'xRoute' => null, ]), new RestAction([ 'id' => 'delete', @@ -288,6 +301,7 @@ public function dataProvider():array 'modelName' => 'Pet', 'modelFqn' => 'app\mymodels\Pet', 'responseWrapper' => null, + 'xRoute' => null, ]), new RestAction([ 'id' => 'update', @@ -300,6 +314,7 @@ public function dataProvider():array 'modelName' => 'Pet', 'modelFqn' => 'app\mymodels\Pet', 'responseWrapper' => ['item' => '', 'list' => '', 'type' => 'object'], + 'xRoute' => null, ]), new RestAction([ 'id' => 'list', @@ -312,6 +327,7 @@ public function dataProvider():array 'modelName' => null, 'modelFqn' => null, 'responseWrapper' => null, + 'xRoute' => null, ]), new RestAction([ 'id' => 'list', @@ -324,6 +340,7 @@ public function dataProvider():array 'modelName' => null, 'modelFqn' => null, 'responseWrapper' => null, + 'xRoute' => null, ]), ], ], @@ -362,6 +379,8 @@ public function dataProviderWithUrlPrefixes():array 'namespace' => '\app\api\v1\controllers', ], 'responseWrapper' => ['item' => '', 'list' => '', 'type' => 'array'], + 'xRoute' => null, + 'modulesList' => [] ]), new RestAction([ 'id' => 'create', @@ -379,6 +398,8 @@ public function dataProviderWithUrlPrefixes():array 'namespace' => '\app\api\v1\controllers', ], 'responseWrapper' => null, + 'xRoute' => null, + 'modulesList' => [] ]), new RestAction([ 'id' => 'view', @@ -393,6 +414,8 @@ public function dataProviderWithUrlPrefixes():array 'prefix' => 'animals', 'prefixSettings' => [], 'responseWrapper' => ['item' => '', 'list' => '', 'type' => 'object'], + 'xRoute' => null, + 'modulesList' => [] ]), new RestAction([ 'id' => 'delete', @@ -407,6 +430,8 @@ public function dataProviderWithUrlPrefixes():array 'prefix' => 'animals', 'prefixSettings' => [], 'responseWrapper' => null, + 'xRoute' => null, + 'modulesList' => [] ]), new RestAction([ 'id' => 'update', @@ -421,6 +446,8 @@ public function dataProviderWithUrlPrefixes():array 'prefix' => 'animals', 'prefixSettings' => [], 'responseWrapper' => ['item' => '', 'list' => '', 'type' => 'object'], + 'xRoute' => null, + 'modulesList' => [] ]), new RestAction([ 'id' => 'list', @@ -433,6 +460,8 @@ public function dataProviderWithUrlPrefixes():array 'modelName' => null, 'modelFqn' => null, 'responseWrapper' => null, + 'xRoute' => null, + 'modulesList' => [] ]), new RestAction([ 'id' => 'list', @@ -451,6 +480,13 @@ public function dataProviderWithUrlPrefixes():array 'namespace' => '\app\modules\petinfo\controllers', ], 'responseWrapper' => null, + 'xRoute' => null, + 'modulesList' => [ + 'pet-info' => [ + 'path' => '@app/modules/petinfo', + 'namespace' => '\app\modules\petinfo', + ] + ] ]), ], ], @@ -475,6 +511,7 @@ public function dataProviderWithNamingMap():array 'params' => [], 'modelName' => 'Post', 'modelFqn' => 'app\models\Post', + 'xRoute' => null, 'responseWrapper' => ['item' => '', 'list' => '', 'type' => 'array'], ]), new RestAction([ @@ -487,6 +524,7 @@ public function dataProviderWithNamingMap():array 'params' => ['id' => ['type' => 'integer']], 'modelName' => 'Post', 'modelFqn' => 'app\models\Post', + 'xRoute' => null, 'responseWrapper' => ['item' => 'post', 'list' => null, 'type' => 'object'], ]), new RestAction([ @@ -501,6 +539,7 @@ public function dataProviderWithNamingMap():array ], 'modelName' => 'Post', 'modelFqn' => 'app\models\Post', + 'xRoute' => null, 'responseWrapper' => ['item' => 'category', 'list' => null, 'type' => 'object'], ]), new RestAction([ @@ -515,6 +554,7 @@ public function dataProviderWithNamingMap():array ], 'modelName' => 'Post', 'modelFqn' => 'app\models\Post', + 'xRoute' => null, 'responseWrapper' => ['item' => '', 'list' => '', 'type' => 'array'], ]), new RestAction([ @@ -529,6 +569,7 @@ public function dataProviderWithNamingMap():array ], 'modelName' => 'Comment', 'modelFqn' => 'app\models\Comment', + 'xRoute' => null, 'responseWrapper' => ['item' => '', 'list' => '', 'type' => 'array'], ]), new RestAction([ @@ -543,6 +584,7 @@ public function dataProviderWithNamingMap():array ], 'modelName' => 'Comment', 'modelFqn' => 'app\models\Comment', + 'xRoute' => null, 'responseWrapper' => null, ]), new RestAction([ @@ -558,6 +600,7 @@ public function dataProviderWithNamingMap():array ], 'modelName' => 'Post', 'modelFqn' => 'app\models\Post', + 'xRoute' => null, 'responseWrapper' => ['item' => '', 'list' => '', 'type' => 'object'], ]), new RestAction([ @@ -573,6 +616,7 @@ public function dataProviderWithNamingMap():array ], 'modelName' => 'Comment', 'modelFqn' => 'app\models\Comment', + 'xRoute' => null, 'responseWrapper' => ['item' => '', 'list' => '', 'type' => 'object'], ]), new RestAction([ @@ -588,6 +632,7 @@ public function dataProviderWithNamingMap():array ], 'modelName' => 'Comment', 'modelFqn' => 'app\models\Comment', + 'xRoute' => null, 'responseWrapper' => null, ]), new RestAction([ @@ -603,6 +648,7 @@ public function dataProviderWithNamingMap():array ], 'modelName' => 'Comment', 'modelFqn' => 'app\models\Comment', + 'xRoute' => null, 'responseWrapper' => ['item' => '', 'list' => '', 'type' => 'object'], ]), ], diff --git a/tests/unit/issues/Issue14Test.php b/tests/unit/issues/Issue14Test.php new file mode 100644 index 00000000..05e39902 --- /dev/null +++ b/tests/unit/issues/Issue14Test.php @@ -0,0 +1,79 @@ +runGenerator($testFile); + $actualFiles = FileHelper::findFiles(Yii::getAlias('@app'), [ + 'recursive' => true, + ]); + $expectedFiles = FileHelper::findFiles(Yii::getAlias("@specs/issue_fix/14_nested_module_in_x_route/mysql"), [ + 'recursive' => true, + ]); + $this->checkFiles($actualFiles, $expectedFiles); + } + + public function testNestedModuleInXRouteFractalAction() + { + $config = []; + $config = require Yii::getAlias("@specs/issue_fix/14_nested_module_in_x_route/index.php"); + $config['useJsonApi'] = true; + $tmpConfigFile = Yii::getAlias("@runtime") . "/tmp-config-35.php"; + file_put_contents($tmpConfigFile, 'runGenerator($testFile); + $actualFiles = FileHelper::findFiles(Yii::getAlias('@app'), [ + 'recursive' => true, + ]); + $expectedFiles = FileHelper::findFiles(Yii::getAlias("@specs/issue_fix/14_nested_module_in_x_route/fractal"), [ + 'recursive' => true, + ]); + $this->checkFiles($actualFiles, $expectedFiles); + FileHelper::unlink($tmpConfigFile); + } + + public function testModuleConfigInUrlPrefixes() # RestAction + { + $testFile = Yii::getAlias("@specs/issue_fix/14_module_config_in_url_prefixes/index.php"); + $this->runGenerator($testFile); + $actualFiles = FileHelper::findFiles(Yii::getAlias('@app'), [ + 'recursive' => true, + ]); + $expectedFiles = FileHelper::findFiles(Yii::getAlias("@specs/issue_fix/14_module_config_in_url_prefixes/mysql"), [ + 'recursive' => true, + ]); + $this->checkFiles($actualFiles, $expectedFiles); + } + + public function testModuleConfigInUrlPrefixesFractalAction() + { + $config = []; + $config = require Yii::getAlias("@specs/issue_fix/14_module_config_in_url_prefixes/index.php"); + $config['useJsonApi'] = true; + $tmpConfigFile = Yii::getAlias("@runtime") . "/tmp-config-35.php"; + file_put_contents($tmpConfigFile, 'runGenerator($testFile); + $actualFiles = FileHelper::findFiles(Yii::getAlias('@app'), [ + 'recursive' => true, + ]); + $expectedFiles = FileHelper::findFiles(Yii::getAlias("@specs/issue_fix/14_module_config_in_url_prefixes/fractal"), [ + 'recursive' => true, + ]); + $this->checkFiles($actualFiles, $expectedFiles); + + FileHelper::unlink($tmpConfigFile); + } +}