How to fix 'Static page in sub-directory" issue in Yii2 - php

I have setup my Yii2 powered website but I will like to get some of my static pages in sub-directories and then display the name of the sub-directory in the url. For example, have in site/hotel/pacific.php and site/mini-rooms/standard.php and then access them using xyz.com/hotel/pacific and xyz.com/mini-rooms/standard.
I have tried to follow some examples online but I am not sure why the are not working. Some of the examples are also for yii and not yii2.
Here is what I did:
In the SiteController.php, I had created a static page before using the code below and I can visit it atxyz.com/hotel/pacific. But now I am moving it into a subdirectory hotel. It was formerly inside the views/site folder:
public function actionPacific()
{
return $this->render('pacific');
}
I then created a folder name pages inside the view folder. Inside the pages folder, I created hotel folder and inside hotel folder I placed pacific.php file so I have views/site/pages/hotel/pacific.php
Also in the SiteController.php, I added this:
public function actions()
{
return [
'error' => [
'class' => 'yii\web\ErrorAction',
],
'captcha' => [
'class' => 'yii\captcha\CaptchaAction',
'fixedVerifyCode' => YII_ENV_TEST ? 'testme' : null,
],
'page' => [
'class'=>'CViewAction',
],
'hotels' => [
'class'=>'CViewAction',
'basePath' => 'pages/hotels'
],
];
}
I then configure my config/web.php by adding the code below:
'urlManager' => [
'class' => 'yii\web\UrlManager',
'enablePrettyUrl' => true,
'showScriptName' => false,
'enableStrictParsing'=>false,
'rules' => [
'<alias:[\w\-]+>' => 'site/<alias>',
'<controller:\w+>/<id:\d+>'=>'<controller>/view',
'<controller:\w+>/<action:\w+>/<id:\d+>'=>'<controller>/<action>',
'<controller:\w+>/<action:\w+>'=>'<controller>/<action>',
],
],
I got 404 error when I visit xyz.com/hotel/pacific.
How can I properly do this for both examples - xyz.com/hotel/pacific and xyz.com/mini-rooms/standard.

What I understood that you are mixing Yii 1 & 2 as CWebView is used in Yii1 and not Yii2. So what you need is probably yii\web\ViewAction, which will represent a single action. There might be better answers someone else could suggest.
So if you have a directory.
views/site/hotel/pacific.php
views/site/hotel/five-star.php
And you want to access the pacific.php view by typing in the URL xyz.com/hotel/pacific and five-star.php with xyz.com/hotel/five-star.
Then you should configure them like below
public function actions()
{
return [
'error' => [
'class' => 'yii\web\ErrorAction'
],
'pacific' => [
'class' => 'yii\web\ViewAction',
'defaultView' => 'pacific',
'viewPrefix' => 'hotel'
],
'five-star' => [
'class' => 'yii\web\ViewAction',
'defaultView' => 'five-star',
'viewPrefix' => 'hotel'
],
'captcha' => [
'class' => 'yii\captcha\CaptchaAction',
'fixedVerifyCode' => YII_ENV_TEST ? 'testme' : null
]
];
}
and then update the urlManager like below
'urlManager' => [
'class' => 'yii\web\UrlManager',
'enablePrettyUrl' => true,
'showScriptName' => false,
'enableStrictParsing'=>false,
'rules' => [
'/' => 'site/index',
'<alias:[\w\-]+>' => 'site/<alias>',
'hotel/<alias:[\w\-]+>' => 'site/<alias>',
'<controller:\w+>/<id:\d+>' => '<controller>/view',
'<controller:\w+>/<action:\w+>/<id:\d+>' => '<controller>/<action>',
'<controller:\w+>/<action:\w+>' => '<controller>/<action>'
]
],
Now if you type in the browser xyz.com/hotel/pacific or xyz.com/hotel/five-star it will show you the corresponding views.
Hope it solves your problem.

I decided to create HotelController.php inside the controller folder and then create hotel folder under views folder. I then added pacific.php inside the hotel folder and add the action code inside HotelController.php as below.
public function actionPacific()
{
return $this->render('pacific');
}
It works as I wanted although I am not sure if there are better alternatives. I removed the rules in the url manager as I did not need them now. I only had to just go to mysite.com/hotel/pacific to display the page. I can create as many page as I need inside the folder and just add their action code.

Related

Yii2 API routing with versions

I'm having a problem getting my Yii2 application API setup. We have a website up and running and I've been tasked to setup a API for 3rd parties to connect to us to perform certain function calls. I've been reading the docs and did some googling and found this site that has a base setup for website and api. I installed it to see how it was setup, so I could try and apply it to my site.
I'm hitting the API section of the directory structure just fine, but I can't for the life of me figure out how the routing is supposed to work.
My directory structure is now as follows:
root
--api
----config
------main.php
----modules
------v1
--------controllers
----------SearchController.php
--------models
----------Search.php
----------ApiUser.php
--------Module.php
----runtime
----web
------assets
--assets
--commands
--config
---common
---site1
--controllers
----base
----common
----site1
--mail
--migrations
--models
--modules
--runtime
--vendor
----vendor_dirs
--views
--web
My apache config is as follows for the api alias:
Alias /api /var/www/website.com/api/web
<Directory "/var/www/webiste.com/api/web">
AllowOverride All
</Directory>
I'm confused to as to how I'm supposed to setup the url_manager section of the config file so that www.website.com/api/v1/search/do-search will hit the \api\modules\v1\controllers\SearchController::actionDoSearch() function.
My config looks as follows
'id' => 'app-api',
'basePath' => dirname(__DIR__),
'bootstrap' => ['log'],
'modules' => [
'v1' => [
'basePath' => '#app/modules/v1',
'class' => 'api\modules\v1\Module',
'controllerNamespace' => 'api\modules\v1\controllers',
],
],
'components' => [
'user' => [
'identityClass' => 'api\v1\models\ApiUser',
'enableAutoLogin' => false,
'enableSession' => false,
],
'log' => [
'traceLevel' => YII_DEBUG ? 3 : 0,
'targets' => [
[
'class' => 'yii\log\FileTarget',
'levels' => ['error', 'warning', 'info', 'trace'],
],
],
],
'urlManager' => [
'enablePrettyUrl' => true,
'enableStrictParsing' => true,
'showScriptName' => false,
'rules' => [
[
'class' => 'yii\rest\UrlRule',
'controller' => 'v1/search',
'pluralize' => false,
'extraPatterns' => [
'GET do-search' => 'do-search'
]
],
],
],
],
I've read through the routing guide on the Yii2 website, but it didn't really shed any light on the subject.
update
So after tweaking my config, I think I managed to make some headway, but I'm still not there yet.
I'm now getting the following error:
ReflectionException
Class api\modules\v1\Module does not exist
My namespace in the module is as follows:
namespace api\modules\v1;
class ApiModule extends \yii\base\Module
{
So it seems that the namespace is not registering property, or the base path for the module is not correct.
Any help explaining things, so I can better understand would be greatly appreciated.
Thanks
SUCCESS
I'm an idiot. The Module.php file was not in the v1 directory, but actually one directory down.
Add your module to modules section:
'modules' => [
'v1' => [
'class' => 'app\modules\v1\Module',
'basePath' => '#app/modules/v1',
'controllerNamespace' => 'app\modules\v1\controllers'
]
Add url rules for REST controller:
'urlManager' => [
'enablePrettyUrl' => true,
'enableStrictParsing' => false,
'showScriptName' => false,
'rules' => [
[
'class' => 'yii\rest\UrlRule',
'controller' => [ 'v1/search']
],
'GET v1/search/do-search' => 'v1/search/do-search',//actually should work without this line
When creating new controller add it to controller section in url rules.

Yii2 route using yii\rest\UrlRule with several parameters

I am trying to use Yii 2 routing for REST API.
Following tutorial at http://www.yiiframework.com/doc-2.0/guide-rest-routing.html, I have already defined (with success) a lot of rule for API entry point like so :
'urlManager' => [
'enablePrettyUrl' => true,
'enableStrictParsing' => true,
'showScriptName' => false,
'rules' => [
[
'class' => 'yii\rest\UrlRule',
'controller' => 'user'
],
],
]
Such a rule defines :
GET /users (list users)
GET /users/123 (show detail of user 123)
Now, my users have games. So I'd like to have urls :
GET /users/123/games (list games of user 123)
GET /users/123/games/864 (details of game 864 for user 123 - such as his scores)
I tried defining my new entry point (withhout success) like so:
'rules' => [
... previous rules ...,
[
'class' => 'yii\rest\UrlRule',
'controller' => [
'game'
],
'tokens' => [
'{userid}' => '<userid:\\d>',
'{gameid}' => '<gameid:\\d>',
],
'patterns' => [
'GET,HEAD /users/{userid}/games' => 'index',
'GET,HEAD /users/{userid}/games/{gameid}' => 'view',
]
]
]
This definition seems wrong because I get a 404 Page not found error.
How should I define my new url routes ?
I would like to use an equivalent format for my definitions, extending 'yii\rest\UrlRule'
I am not sure if this is even possible, the tutorial not mentionning this case.
So I figured out how to use more complex rules.
First, the solution, then the explanation.
Here is the solution:
'rules' => [
... previous rules ...,
[
'class' => 'yii\rest\UrlRule',
'controller' => 'game',
'prefix' => '/users/<userid:\\d+>',
'tokens' => [
'{gameid}' => '<gameid:\\d+>',
],
'patterns' => [
'GET,HEAD' => 'index',
'GET,HEAD {gameid}' => 'view',
]
]
]
And now the explanation:
First my userid / gameid attributes were badly defined. There was a missing "+" after "\d"
The controller seems to be automatically added as a prefix to the patterns. So you have to define both a controller and a prefix (that will be added before the controller).
Parameters in the prefix does not seem to be parsed to find tokens. So I wrote directly the regexp in the prefix instead of adding "userid" as a token.
Finally, there are various "/" automatically added during concatenation of "prefix/controller/pattern" so you don't have to write one.
Do not forget the pluralization rule too ! "game" is singular" but valid urls will be
/users/123/games
/users/123/games/789
Hope it will help.
I think there´s a simple solutions, please try this:
'rules' => [
...
'/users/<userId:\\d+>/games' => 'game/index' ,
'/users/<userId:\\d+>/games/<gameId:\\d+>' => 'game/view' ,
....
];
Just use yii2-nested-rest
It provides REST API for MANY-to-MANY relations in Yii2 framework.
Hope comments will make the magic more understandable:
'rules' => [
// this usual rule for base Yii2 rest usage
['class' => 'yii\rest\UrlRule', 'controller' => ['sitecomponent' ,'sitepage' , 'sitedomain'], 'pluralize'=>false
],
// then rules for yii2-nested-rest
[
// url sitepage/NNN/sitecomponent[/MMM]
// ^^^^^^^^^ ^^^^^^^^^^^^
// resourceName model-endpoint
'class' => 'tunecino\nestedrest\UrlRule',
'modelClass' => 'app\models\SitePage',
'resourceName' => 'sitepage',
'relations' => ['components' => ['sitecomponent'=>'sitecomponent'] ],
// ^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^ ^^^^^^^^^^^
// relation name url-endpoint controller]
// defined in model SitePage model-endpoint with Actions from nested
],
[
// cross url sitecomponent/NNN/sitepage[/MMM]
'class' => 'tunecino\nestedrest\UrlRule',
'modelClass' => 'app\models\SiteComponent',
'resourceName' => 'sitecomponent',
'relations' => ['pages' => ['sitepage' => 'sitepage'] ],
// ^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^ ^^^^^^^^^
// relation name url-endpoint controller
// from model SiteComponent model-endpoint with Actions from nested
],
],
GET xx.com/v2/publication/12/p/34
[
'class' => 'yii\rest\UrlRule',
'pluralize' => false,//controller是否复数
'controller' => 'v2/publication',//此处一定要加上v2
'tokens' => [
'{id}' => '<id:\\d[\\d,]*>',
'{phase}' => '<phase:\\d[\\d,]*>',
],
// 通过extraPatterns和tokens来实现多个参数传递
'extraPatterns' => [
'GET,HEAD {id}/p/{phase}' => 'phase',
],
],
IN ACTION
public function actionPhase($id, $phase){}

urlmanager with modules not working in yii2.0

This regarding module creation inside backend folder.Example i have created a module name as "api". And also sccessfully created controller for that modules.
here is my urlmanager code:
'urlManager' => [
'class' => 'yii\web\UrlManager',
'enablePrettyUrl' => true,
'rules' => [
'<module:\w+>/<controller:\w+>/<action:\w+>'=>'<module>/<controller>/<action>',
'<module:\w+><controller:\w+>/<action:update|delete>/<id:\d+>' => '<module>/<controller>/<action>',
],
]
when i access url with respect to module as "api" , controller as "country" and action as "create"
http://local2host.com/bootstrap/backend/web/index.php/api/country/create
it showing 404 Not Found error
Where i am going wrong?
The second rule will never work, Also you do not have to define the rules and the normal ones will work. So this
'urlManager' => [
'class' => 'yii\web\UrlManager',
'enablePrettyUrl' => true,
'showScriptName' => false,
],
will make this link /website.com/core/contact/index work just fine.
But I am not sure why your route is not catching the first rule... strange. It should.
Better late then never.
For make module works you need to append it in config:
'modules' => [
......
'modulename' => [
'class' => 'app\modules\modulename\Module',
],
......
],

Yii2 global filter/behavior to force user to authenticate first

In my Yii2 application I'm trying to force all users to be authenticated. If they're not already authenticated they should be redirected to the login page.
In Yii1 I did this by creating a class that would check if a user was logged in and attaching that class to the onBeginRequest behavior in my main config file.
// Yii 1
'behaviors' => array(
'onBeginRequest' => array(
'class' => 'application.components.RequireLogin',
)
),
How can I get the same behavior in Yii2? I know I can use behavior to do this, but I wan't to add this behavior to my main config file so all requests are first checked for authentication.
The working behaviors method looks like this:
// Yii2
public function behaviors() {
return [
'access' => [
'class' => AccessControl::className(),
'rules' => [
[
'actions' => ['login', 'error'],
'allow' => true,
],
[
'allow' => true,
'roles' => ['#'],
],
],
],
];
}
Ok, so I had to add the following code below 'components' => [...]
'as beforeRequest' => [
'class' => 'yii\filters\AccessControl',
'rules' => [
[
'actions' => ['login', 'error'],
'allow' => true,
],
[
'allow' => true,
'roles' => ['#'],
],
],
],
Read more about the format: http://www.yiiframework.com/doc-2.0/guide-concept-configurations.html#configuration-format
I'm actually not versed into Yii2 (but very much so into Yii1).
One solution that can be employed in Yii1 and I guess also in Yii2 is having a filter method in a master Controller class. Typically a single controller serves as a master controller. If you don't have one, create it and everyone should extend it. You can implement this probably not as a filter but in other methods of this 'master controller' (init() ?)
If all activity is going through controller class then you're set.

How to use the Yii2 GroupUrlRule() class

I want to group paths under one common path. I found in the Yii2 documentation that this can be achieved with the GroupUrlRule() class. I can not understand where to set it. I tried to sat it as a rule to the urlManager in confing/web.php but nothing happened.
Imagine that you have some module. Your confing/web.php file might look like this:
'components' => [
'urlManager' => [
'class' => 'yii\web\UrlManager',
'showScriptName' => false,
'enablePrettyUrl' => true,
'rules' => [
[
'class' => 'yii\web\GroupUrlRule',
'prefix' => 'module',
'rules' => [
'/' => 'controller/index',
'create' => 'controller/create',
'edit' => 'controller/edit',
'delete' => 'controller/delete',
],
],
],
],
]
Now, by URL hostname.com/module will be called 'module/controller/index'.
You can do it in Bootstrap file. Example:
project/Bootstrap.php
namespace app;
use yii\base\BootstrapInterface;
use yii\web\GroupUrlRule;
class Bootstrap implements BootstrapInterface
{
public $urlRules = [
'prefix' => 'admin',
'rules' => [
'login' => 'user/login',
'logout' => 'user/logout',
'dashboard' => 'default/dashboard',
],
];
public function bootstrap($app)
{
$app->get('urlManager')->rules[] = new GroupUrlRule($this->urlRules);
}
}
project/config/web.php
return [
// ...
'bootstrap' => [
'log',
'app\Bootstrap',
],
// ...
]
P.S. Bootstrap files are extremely useful with modular application structure. It is much more clear to configure module's routes inside the module's folder. For that purpose just create Bootstrap file for every module in its folder. But don't forget to update bootstrap section of your application config file.

Categories