Yii: validation rules that always apply except one scenario - php

I know that you can have a validation rule that applies only for one scenario:
array('username', 'exist', 'on' => 'update'),
Now i would like to know if it's possible to do the opposite: a rule that applies everytime except for a given scenrio?
The only solution that is see right now is list all the others scenario, but it's not pretty if we need to add some news scenarios later.
array('username', 'exist', 'on' => array('create', 'search', ...),//all the scenarios except update

As of Yii 1.1.11 you can use except keyword:
array('username', 'exist', 'except' => 'update'),
Take a look at this page. There is a little example there.
Doc link

Work the same way in Yii 2.0.
['username', 'required', 'except' => 'update']
Every key in the array before the name of the validator is a property for the Validator Class itself. You can see the available properties in https://www.yiiframework.com/doc/api/2.0/yii-validators-validator
I know is an old question but every time I forgot that yii2 have an except property in the validator class.
https://www.yiiframework.com/doc/guide/2.0/en/input-validation for more advanced technics

Related

yii rules validate from database

I have a table of places each place has:
id|name|work_start|work_end
The user can make a reservation in a certain place and he needs to input the time he wants it. I want to validate if the time is between work's start and work's end.
I'm a new to yii, I can do it easily in the controller but I want the best practice to do it. Can I put a rule in the ActiveRecord or is there any other method to do it?
You could use a couple of compare rules
['fromDate', 'compare', 'your_date_attribute' => 'toDate', 'operator' => '<',
'enableClientValidation' => false],
['toDate', 'compare', 'your_date_attribute' => 'toDate', 'operator' => '>',
'enableClientValidation' => false],
see this for some suggestion http://www.yiiframework.com/doc-2.0/guide-tutorial-core-validators.html

Yii2: scenarios() model method

There are 2 needed functions: set password when registering and change password, if user forgot it. When user signs up, password length must be at least 4 chars; when changes pass - at least 5 chars.
View is common for registration and changing pass. Obviously, also 2 actions exist, in which either scenario 'signup', either 'change' used.
Code snippet in model:
public function rules() {
return [
['password', 'string', 'min' => 4, 'on' => 'signup'],
['password', 'string', 'min' => 5, 'on' => 'change'],
];
}
But I want to do do it via scenarios(). How to do it? I'm a beginner in Yii, so did not understand, when and how to use scenarios(). Thanks.
UPD. I need to use scenarios() for ONE field with ONE rule, but DIFFERENT arguments to this one rule. how to define a scenario in Yii2? - it is NOT my case.
As documentation about scenarios() says: The default implementation of this method will return all scenarios found in the rules() declaration. So generally you do not need to override this method, because it will look for on array keys to set active attributes for current scenario an validate them properly.
So in your case 'on' => 'some scenario' for different validations of the same attribute is exactly what you need.

There's a way of applying a laravel filter for HTTP method? Like on POST?

I develop a system using laravel, and my system has a kind of user how can do some special operations, called MASTER.
He is the only one kind of user how can Create/Edit things. The users with "READ" permissions can read then (Show method), though.
There's an way of applying a filter for the post methods?
NOTE: I use laravel "Route::resource", so grouping them and apllying a filter, dispite the fact that is more logical and easy, is it not a easy task to do.
You can register filters directly in the controller as documented here
This would be for all POST requests:
public function __construct()
{
$this->beforeFilter('permission', array('on' => 'post'));
}
Or for some specific controller methods:
$this->beforeFilter('permission', array('only' => array('create', 'edit', 'store', 'update', 'delete'));
However in this scenario the simplest thing might be to just specify the methods that are allowed for everyone to call:
$this->beforeFilter('permission', array('except' => array('index', 'show')));

Doubts about Yii2 RBAC

I've been developing web apps using Yii 1.1.14 so far, but now it's time for an upgrade.
The company where I work has developed its own Access Control system, and I was really OK with it until I saw what it was really like... A combination of 8 tables in the database (not counting the users table), with a bunch of foreign keys.
1 table for controllers
1 table for the actions
1 table for the menu categories
1 table for types of users
And the other tables basically just connect 2 or 3 of those tables at a time.
It works well, but in my point of view it's highly time consuming to maintain all those tables, and at some point, when your application goes online, if it hits a certain amount of users it could get really slow. specially because 2 of those tables have the user's table primary key as foreign key.
So I've decided that, when I start developing on Yii 2, I'm going to start using RBAC, so I started looking for tutorials online... Only finding many different versions of the same code with author's role, and permissions for create or update posts.
I found a combination of 5 videos on Youtube, but they are about Yii 1 RBAC. They were helpful because I managed to understand most of RBAC's functionality, but I still have some doubts that I'll
enumerate below. And keep in mind that for this Access Control system I'm using the DBManager class.
My Doubts
Yii 1's RBAC used to have 3 tables: auth_assignment, auth_item and auth_item_child. Now in Yii 2 RBAC, a new table appears that is called auth_rule and I still don't understand what that specific table is doing there, how to use it or how to populate it.
I see that it's possible to restrict the user's access to some actions by using the controller's behavior method, and assigning access to some actions depending on the user's role, but when it comes to this I have to split my question into 2:
2.1. First: If you can just restrict the access to actions by setting it up in the behaviors method, then what's the use of saving permissions to the auth_item table?
2.2. Second: If you DO decide to control access according to permissions, then how exactly do you do it, because I find myself writing the following type of code inside of every function and I don't think using RBAC is supposed to be this tedious. There has to be another way.
public function actionView($id)
{
if(Yii::$app->user->can('view-users')){
return $this->render('view', [
'model' => $this->findModel($id),
]);
}else{
#Redirect to a custom made action that will show a view
#with a custom error message
$this->redirect(['//site/notauthorized']);
}
}
Because of the Access Control System that we use right now, when a user logs in, a complex query is executed that will end up returning an array that will be saved as a session variable, and will be used to create a menu with as many dropdownlists as menu categories, that the controllers that the user has access to belong to. How can this be done with RBAC?
I can only really answer 2.2 of your question, as 3 doesn't sound at all like something an RBAC should do. You could, however, get the information you needed from the rules table most likely, provided you followed a naming convention that matched your controllers or actions.
On to answering 2.2 though:
You can simply set the behavior like such:
public function behaviors()
{
return [
'access' => [
'class' => AccessControl::className(),
'rules' => [
[
'allow' => true,
'actions' => ['view'],
'roles' => ['view-users'], //<-- Note, rule instead of role
],
]
]
}
This doesn't solve a different problem of 'view-own-users' style permissions, as this needs to inspect the ActiveRecord model (well, at least it does in my application). If You want to achieve this, take a look at my post in the Yii forums here:
http://www.yiiframework.com/forum/index.php/topic/60439-yii2-rbac-permissions-in-controller-behaviors/#entry269913
I use it in one of the simplest method,I use them in the behaviours of my controller.
public function behaviors()
{
return [
'access' => [
'class' => \yii\filters\AccessControl::className(),
'rules' => [
[
'allow' => true,
'roles' => ['sysadmin'],
'actions' => ['index','view','update'],
],
[
'allow' => true,
'roles' => ['staff'],
'actions' => ['index','create','update','view'],
],
],
],
];
}
Here roles are the one created in the auth-item table in the database and they have been assigned for users in auth-assignment table. In the behaviours we just use it as above. In the above code sysadmin can have access to index, view and update action, whereas staff can have access to index,create, update and view action.
Yii2 needs a little setup when it comes to using RBAC under your controllers AccessControl. I got around it by making my own AccessRule file.
namespace app\components;
use Yii;
class AccessRule extends \yii\filters\AccessRule
{
protected function matchRole($user)
{
if (empty($this->roles)) {
return true;
}
foreach ($this->roles as $role) {
if(Yii::$app->authManager->checkAccess($user->identity->code, $role))
return true;
}
return false;
}
then in your controller u can use something like this:
public function behaviors()
{
return [
'access' => [
'class' => AccessControl::className(),
'ruleConfig' => [
'class' => 'app\components\AccessRule'
],
'rules' => [
[
'actions' => ['index', 'resource-type'],
'allow'=> true,
'roles' => ['admin'],
],
],
],
];
}
Where admin is defined as a auth_item and the user is in the auth_item_assignments.
As I have created a new Rbac system for yii2. you can direct permission for a action and action will show you are not authorisez for this action.
By this you find that you will only provide access for action that need to identify.
I uploaded my detail here you can find lot of solution here.
This is the best solution i could come up with when facing the need to filter access by permissions, it's bothersome but can be useful if you're trying to create roles in a productive enviroment and want to use rbac.
use yii\web\ForbiddenHttpException;
if(Yii::$app->user->can('view-users')){
return $this->render('view', [
'model' => $this->findModel($id),
]);
}else{
throw new ForbiddenHttpException('You dont have access to this site');
}

which one is cleaner : put conditional statement on view or model?

I'm a Yii developer who want to follow MVC pattern.
In one part of my current project I have to check a special condition and according to it's result show a list of something to user. I want to determine if the user is admin or a guest.
There is two choice for me here, one is to determine two method one for admin and one for other user and check if the user is admin or not in the view, something like this:
$this->widget('zii.widgets.grid.CGridView', array(
'id' => $tableName . "_grid",
'dataProvider' => (Yii::app()->user->id == User::ADMIN) ? $model->search() : $model->getMyList(),
'filter' => $model,
'columns' => array(
....
or change the getMineList method in the model. By this fact that I can't put this statement in the controller which one is better and cleaner?
The best way would to do the logic in the model by changing the getMineList or, as GBD stated, implement it into the search method of the model

Categories