Yii2: Hide search results based on permission - yii2

In my table I have:
PRODUCT
id_product
name
status
Where the status assumes the following values:
1 (Active)
2 (Inactive)
3 (Archived)
In the Product index view, I want the user to see certain statuses based on the permissions. Example:
Administrator sees records with statuses 1, 2, and 3.
Moderator views: 1 and 2
User views: 1
How can I do this? What alternatives do I have?

You could add conditions to your search model (I guess you have a ProductSearch.php file) so that results will be filtered based on user's role.
I've never used Yii's RBAC but I suppose you have a method to get user role, as described here: https://stackoverflow.com/a/25248246/4338862
So in your search model I would add, after grid filtering conditions, one or more conditions:
if($isUser) {
$query->andFilterWhere([
'status' => 1,
]);
}
elseif($isModerator) {
$query->andFilterWhere(['or',
['status' => 1],
['status' => 2]
]);
}
I can give you a more detailed answer if you need it.

Related

Return softDeleted relation rows

I have a table, called "bsService", where I save my created services. Those services have some relations, like categories, activities and others.
I'm trying to get services where categories was softDeleted. Example: service 1 relates to category 1, I softDeleted category 1, and now this service doesn’t return on findAll even if add 'withDeleted: true' on the query.
Here's my findAll method. I want all data even if a relation is softDeleted.
findAll = async (
where?: WhereConditions,
transactionEntityManager: EntityManager = getManager(),
order?: 'ASC' | 'DESC',
withDeleted?: boolean,
): Promise<BSService[]> => transactionEntityManager.find(BSService, {
withDeleted,
where,
relations: ['sla', 'activity', 'activity.category', 'department', 'department.company', 'attendance', 'logs', 'logs.user', 'requestingAgent', 'alocatedAgent', 'category', 'requestingAgent.jobs', 'alocatedAgent.jobs'],
order: {
updateAt: order,
},
});
The 'withDeleted' becomes true, depending on which page client is using. For that example, it is always true.
withDeleted in .find() only applies to the top layer, not relations.
Here's someone with a similar issue.
Here's a PR that shows how you can solve it by using a query builder with .withDeleted() before the relations you want to include. There's some discussion about supporting this with .find() but it seems like it won't be any time soon.
await manager
.getRepository(BSService)
.createQueryBuilder('bsservice')
.withDeleted() // Above innerJoinAndSelects
.innerJoinAndSelect('bsservice.sla', 'sla')
.innerJoinAndSelect('bsservice.activity', 'activity')
// ... more inner joins ...
.getMany();

Yii 2 Active Query joinWith issue

I have a Active Record model "Event" with a hasOne relation 'getUser'.
Now, if I do :
$eventModels = Event::find()->joinWith([
'user' => function($q){
return $q;
}])->all();
----------------------------------------------------
foreach($eventModels as $m){
var_dump($m->user); //Everything good as $m->user returns the related user object
die('skdw');
}
But, if I add the "select" in the joinWith query, then related "user" object becomes null. Here is the issue :
$eventModels = Event::find()->joinWith([
'user' => function($q){
$q->select('email');// or, ['email'] or ['user.email'] etc. fields.
return $q;
}])->all();
----------------------------------------------------
foreach($eventModels as $m){
var_dump($m->user); // Returns NULL
die('skdw');
}
But, if I make it $q->select('*'), then $m->user working .
I believe it used to work in some previous versions of Yii 2 (Right now, I am working on Yii 2.0.9)
Is this expected behavior ? If yes, then what is the solution to fetch only some select fields for the related joinWith model ? I don't want to fetch all the related fields as some of the related fields might contain "TEXT" data type.
You need to select the primary key column for the relation for Yii to build them.
e.g. assuming your column is called id
$eventModels = Event::find()->joinWith(['user' => function($q){
$q->select(['id', 'email']);
}])->all();
Also, you don't need to return the $q variable.

Laravel ordering results by specific values

I have this line of code which gets results from a database:
'clanMembers' => User::find(Auth::user() -> clan_id) -> where('clan_id', '=', Auth::user() -> clan_id) -> orderBy('username') -> get()
Currently it orders by the username. I wish to change this to order by the clan_rank field. This clan_rank field will only ever contain 3 different values. These are:
1. Owner
2. Admin
3. Member
I wish to have my results ordered with Owners first, then Admin, then members. How can I change my line of code to achieve these results?
You need to use orderByRaw:
instead of orderBy part you should use
orderByRaw("FIELD(clan_rank , 'Owner', 'Admin', 'Member') ASC");

Join DB tables with hasMany association - store in array

In a cakePHP application I am building, a profile can have multiple locations; the tables are called "profiles" and "locations" and in the model classes I have defined a HasMany relationship. Now I want the user to be able to search profiles based on their locations. After reading some questions here and the CakePHP Cookbook, I have decided I need to use SQL joins (in reality more tables are involved, and the result of a search should be based on conditions concerning different tables).
I have written the following function inside my Profile model:
public function findProfiles($long, $lat){
$options['joins'] = array(
array('table' => 'locations',
'alias' => 'Location',
'type' => 'Inner',
'conditions' => array('Location.profile_id = Profile.id'))
);
$options['order'] = array('Location.lng ASC'); //this is just as trial
return $this->find('all',$options);
}
The code works, but I get a copy of a profile for each location it possesses. That is, if a profile possesses 5 positions, I get five instances of that profile (each instance containing all five positions!)
How can I achieve this?
[edit]
eg. let's assume I only have one profile, with two positions. I get:
result[0][Profile]
[Position][0]
[1]
[1][Profile]
[Position][0]
[1]
Where the data in result[0] and result[1] is identical.
The problem happens because of the type of join used. With inner join you'll get this return with your query
profile_id location_id
---------------------------
1 2
1 3
And cake understands that as two records of Profile, so you get repeated Profiles with the same info.
If this were all the extent of your problem, I'd say "go with Containable behaviour and forget joins", but since you said there are more tables involved, maybe the type of join can't be changed. So to get the unique Profile without repetitions, you'll have to GROUP BY the query to get
profile_id location_id
---------------------------
1 2 & 3
with a code similar to this
$options['joins'] = array(
array('table' => 'locations',
'alias' => 'Location',
'type' => 'Inner',
'conditions' => array('Location.profile_id = Profile.id')),
'group' => 'Profile.id'
);
and you'll get rid of repetitions. For future problems like this, is best to first check the actual query that gets send to the DB, check yourself if the result that the DB gives you is what you want, and if not, see what you can do in cake to change it.

Thinking Sphinx - How to give different weights to models when searching multiple models (global search)

Let say I have two indexed models: User and Student.
I want to search on both models but give precedence to User. How can I do that?
Easy:
results = ThinkingSphinx.search(search_term,
:classes => [User, Student],
:index_weights => {'user_core' => 5},
)
student_core will implicitly have a weight of 1.