-2

I am working on yii2. I have a menu named SIM Management in which there are some sub-menus like shown below.

enter image description here

There are 3 Roles added in the system which are

  1. SIM Manager with role id 6
  2. Production Manager with role id 7
  3. SIM Tester with role id 8

SIM Manager has all access to the module. Now I want to give access of sub-menus to the other users.

Production Manager will just view SIM Return and Meter To SIM Mapping. SIM Tester will just view SIM Return.

There are multiple modules in the system which are handled according to the user role. This handling is done via Databases. Below is the snap of the table

enter image description here

Here you can see there is SIM Management and in allow access i have added 4 role id's while 1 is the admin. Also in front of SIM Return and Mapping, the roles are defined. But as the parent id 62 is same for all of them so that's why all the module is visible to others.

In my main.php I am calling a function named menuItems.

<?php
  $menu_items = \app\models\UserMenu::mainItems();

?>

The function detail is

public static function mainItems(){
    $query =  UserMenu::find();
    $query->where(['parent_id' => 0]);

    if(!Yii::$app->user->isGuest) {          
            $query->andWhere("(FIND_IN_SET(". Yii::$app->user->identity->user_role.",allow_access)) <> 0 ");
            $query->orderBy('display_order desc');

    }

    return $query->all();
}

The roles are defined in the Roles Model

const ROLE_SUPER_ADMIN = 1;
const ROLE_ADMIN = 2;
const ROLE_TEAM_LEAD = 3;
const ROLE_FIELD_WORKER = 4;
const ROLE_INVENTORY_MANAGEMENT = 5;
const ROLE_SIM_MANAGER = 6;
const ROLE_PRODUCTION_MANAGER = 7;
const ROLE_SIM_TESTER = 8;

Now, here I want to set a query to check the user role and from that user role it will allow the menus to be viewed

In above function, a check can be placed like below

if (Yii::$app->user->identity->user_role == Roles::ROLE_PRODUCTION_MANAGER) 
{
     // here I want to set a query that will only send the specific menu Items.
} 

Update 1

Below is my main.php code. Here all the menus and sub-menus resides

<?php

        $_a = "/" . Yii::$app->controller->id . "/" . Yii::$app->controller->action->id;
        ?>
        <?php
        $menu_items = \app\models\UserMenu::mainItems();

        ?>

        <!-- Sidebar Menu -->
        <ul class="sidebar-menu">


            <li><a href="<?= Yii::$app->request->baseUrl ?>"><i class="fa fa-dashboard"></i><span> Dashboard</span></a>
            </li>
            <li class="header">SURVEY</li>
            <?php if(!Yii::$app->user->isGuest){ ?>
            <?php foreach ($menu_items as $menu) {
                $arr = explode("/",$menu->link);

               if(!Rbac::allowAccess($arr[1], $arr[2])){

                   continue;

               }

                ?>
                <li class="<?= $menu->isMainActive(Yii::$app->controller->id) ? 'active' : '' ?>"><a href="#">
                        <i class="<?= $menu->fa_icon ?>"></i> <span><?= $menu->title ?></span>
                        <span class="pull-right-container"><i class="fa fa-angle-left pull-right"></i>

                    </a><?php if ($menu->getHasSubMenu()) { ?>
                        <ul class="treeview-menu">
                            <?php foreach ($menu->getSubMenuItems() as $sub) {
                                $arrs = explode("/", $sub->link);
                                if (!Rbac::allowAccess($arrs[1], $arr[2])) {
                                  //  continue;
                                }
                                ?>
                                <li class="<?= $sub->isSubActive($_a) ? 'active' : '' ?>"><a
                                        href="<?= Yii::$app->request->baseUrl ?><?= $sub->link ?>"><?= $sub->title ?></a>
                                </li>
                            <?php } ?>
                        </ul>
                    <?php } ?>
                </li>
                <?php if($menu->break==1) {?>
                    <li class="header">INSTALLATION</li>
                    <?php } ?>
             <?php } ?>
            <?php } ?>

Any help will be highly Appreciated.

Reborn
  • 19,713
  • 8
  • 36
  • 61
Moeez
  • 537
  • 5
  • 33
  • 95

1 Answers1

1

You do not need to add a check but you have to add the query to use FIND_IN_SET like below in a separate function that calls the subMenuItems() from the UserMenu model.

public function subMenuItems(){
    $query =  self::find();
    $query->where(['=','parent_id', $this->id]);

    if(!Yii::$app->user->isGuest) {          
        $query->andWhere(new \yii\db\Expression('FIND_IN_SET(:user_role,allow_access)<>0'));
        $query->addParams([':user_role'=>Yii::$app->user->identity->user_role]);
        $query->orderBy('display_order desc');
    }

    return $query->all();
}

This will return you the menu items that you need for the current user is allowed. you just need to display it no more checks need to be added.

Although this is not the conventional approach that you have used, you should have created a MenuHelper that should return the Menu items array that could be used inside the Nav,Menu or SideMenu widget provided by Yii2, but hope it helps you out.

Reborn
  • 19,713
  • 8
  • 36
  • 61
  • I'll apply it and let you know :) – Moeez Feb 22 '18 at 09:31
  • sure take your time. – Reborn Feb 22 '18 at 09:32
  • Tried and it's giving me `Illegal string offset ':qp1'` in `E:\xampp\htdocs\inventory-web\vendor\yiisoft\yii2\db\QueryBuilder.php` at `$params[$phname] = $value` – Moeez Feb 22 '18 at 09:35
  • OOPS wait a mistak :D – Reborn Feb 22 '18 at 09:37
  • `$query->addParams(':user_role',Yii::$app->user->identity->user_role);` it's giving me `method call uses 2 parameters, but signature uses 1 parameters` – Moeez Feb 22 '18 at 09:37
  • updated there was a missing `[]` in `addParams` updated see now @MrFaisal – Reborn Feb 22 '18 at 09:37
  • @Bro, there shouldn't be a `;` after `$query->addParams([':user_role',Yii::$app->user->identity->user_role])` ? – Moeez Feb 22 '18 at 09:38
  • yes there should be `;` in end and i had to pass the array in `addParams` – Reborn Feb 22 '18 at 09:39
  • Tried the updated code. It's saying `SQLSTATE[HY093]: Invalid parameter number: Columns/Parameters are 1-based Failed to prepare SQL: SELECT * FROM `user_menu` WHERE (`parent_id`=:qp2) AND (FIND_IN_SET(:user_role,allow_access)) ORDER BY `display_order` DESC` – Moeez Feb 22 '18 at 09:39
  • it should be like this in `addParams([':user_role'=>Yii::$app->user->identity->user_role])` @MrFaisal – Reborn Feb 22 '18 at 09:41
  • @Mr.Omer, Ok tried the corrected way. Now I can see the page but again all the sub-menus are visible :( – Moeez Feb 22 '18 at 09:45
  • what is the `role_id` of the current user you are logged in with ? – Reborn Feb 22 '18 at 09:46
  • The `role_id` is `7` – Moeez Feb 22 '18 at 09:48
  • according to the above values in the table you should be show the first one only `SIM Management` ? am i correct? – Reborn Feb 22 '18 at 09:55
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/165632/discussion-between-mr-faisal-and-muhammad-omer-aslam). – Moeez Feb 22 '18 at 09:55
  • No No, SIM Management is the name of the module. And all the sub-menus are only visible to the SIM Manager having `role_id = 6`. This is handled directly from the DB. I want to handle other 2 cases – Moeez Feb 22 '18 at 10:23
  • A user with `role_id=7`i.e. Production Manager. `SIM Return` and `Meter to SIM Mapping` will only be visible to him – Moeez Feb 22 '18 at 10:24
  • And a user with `role_id = 8` i.e. SIM Tester. Only `SIM Return` would be visible to him – Moeez Feb 22 '18 at 10:25
  • i am saying that because you have the check of `parent =0` in the query , can you copy paste the raw `SQL` query generated by the above statement using `->createCommand()->rawSql` @MrFaisal – Reborn Feb 22 '18 at 10:42
  • The `parent_id` is `0` for Main `Module Name`. – Moeez Feb 22 '18 at 10:49
  • Here it is `"SELECT * FROM user_menu WHERE (parent_id=0) AND (FIND_IN_SET(7,allow_access)) ORDER BY display_order DESC"` – Moeez Feb 22 '18 at 10:50
  • if you run the above SQL in the query console or phpmyadmin do you get the correct results – Reborn Feb 22 '18 at 10:55
  • It's only returning me the Main Module. `62 SIM Management /sims/index sims 1,6,7,8 0 fa fa-list 0 0 simissueancetransaction,simreturn,metertosimmapping,sims index,create ` – Moeez Feb 22 '18 at 11:11
  • Ok, I did have a `getSubMenuItems()` in `UserMenu`. So I pasted your above code and it is working :) – Moeez Feb 27 '18 at 06:24
  • that was what i was asking from the start to add it for the `subMenuItems()` :D lol – Reborn Feb 27 '18 at 06:25
  • Lol, it's my bad :P – Moeez Feb 27 '18 at 06:26
  • @Bro, it's working but the `SIM Return` sub-menu isn't showing against `SIM Manager`, though the allow access is `1,6`. where 1 is `admin` and 6 is `SIM Manager`. also for sim issuance and excel file import the allow access is same i.e. 1,6. Don't know why it's not showing the other one :( – Moeez Feb 27 '18 at 13:54
  • The `rawsql` is `SELECT * FROM user_menu WHERE (parent_id = 62) AND (FIND_IN_SET(6,allow_access)<>0) ORDER BY display_order DESC` and it's returning me all the sub-menu items else `SIM Return`. I also want to mention that for `admin` it's visible. – Moeez Feb 27 '18 at 13:57
  • you mean the sub-menu `SIM Return` is not showing if you log in with a user having role `SIM_Manager` i.e `6`? and if you run the above `mysql` query in phpmyadmin does it show you the desired list of menu items? @MrFaisal – Reborn Feb 27 '18 at 14:01
  • ok can you add the schema for the `user_menu` table, the `create table` command so i can create the table and see it in fiddle. @MrFaisal – Reborn Feb 27 '18 at 14:05
  • CREATE TABLE `user_menu` ( `id` INT(10) NOT NULL AUTO_INCREMENT, `title` VARCHAR(50) DEFAULT NULL, `link` VARCHAR(200) DEFAULT NULL, `controller` VARCHAR(50) DEFAULT NULL, `allow_access` TEXT, `parent_id` INT(10) DEFAULT '0', `fa_icon` VARCHAR(50) DEFAULT NULL, `display_order` INT(3) DEFAULT '0', `break` TINYINT(1) DEFAULT '0', `active_list` TEXT, `sub_active_list` TEXT, PRIMARY KEY (`id`) ) ENGINE=INNODB AUTO_INCREMENT=69 DEFAULT CHARSET=latin1; – Moeez Feb 27 '18 at 14:11
  • i just tested the above query and it works fine against the `ROLE 6` and shows the correct results for the menu items, you should check you code first that there are no trailing spaces in column names and or aliases, and then check in the data base the values in the `allowed_access` too see the [**`SQL-fiddle`**](http://sqlfiddle.com/#!9/352ae3/2) @MrFaisal there must be something that is preventing the data to be fetched even with the RAW query in the `phpmyadmin` as the same query shows the correct results in the fiddle – Reborn Feb 27 '18 at 14:23
  • But then why it's showing me with `ROLE 1`. If there is an issue in code than it should not show against any role – Moeez Feb 27 '18 at 14:26
  • yes that is what I am talking about the issue does not look to be in the code but in the data entered to see if the `allowed_access` column against the `SIM Return` has the comma separated string without spaces? and what is this check doing `if (!Rbac::allowAccess($arrs[1], $arr[2])) {` are you still using it ? @MrFaisal – Reborn Feb 27 '18 at 14:29
  • Yes in allow access is without spaces. I don't really know about that check :( – Moeez Feb 27 '18 at 14:39
  • @Mr Omer, For checking I first just allowed `SIM Return` to `Role 6` and it shows. Then again I added `1,6` and reloaded the page and it's still showing. Don't know what was the issue :| – Moeez Feb 27 '18 at 15:03
  • that is awkward can you check by changing the data type for the column to varchar although it sounds stupid I know – Reborn Feb 27 '18 at 15:05