⚠ In case you've missed it, we have migrated to our new website, with a brand new forum. For more details about the migration you can read our blog post for website migration. This is an archived forum. ⚠

  •     

profile picture

set/unset actions per row of list?



meyercr
  • profile picture
  • Member

Posted 21 March 2013 - 00:47 AM

I am working on a system which has Roles (Admin, Power, User), which each have different permissions.

 

When I display the Projects table, I would like the "add", "edit" action buttons to only show up for Users which either are Admins or own than Project.

 

Is there a callback (per list row) which controls display of the action buttons?  something like   "callback_column('Action')"  Where 'Action' would be the Action column.

 

Or, alternatively,  callback_before_action_add(),  callback_before_action_edit().  Or more general callback_before_action('<action-name>')

 

Thank you,


meyercr
  • profile picture
  • Member

Posted 21 March 2013 - 20:40 PM

The code is so consistently written, that it was straight forward to add two new callbacks

  • callback_can_edit( array($this, '_cbHavePriv'))
  • callback_can_delete(array($this, '_cbHavePriv'))

The callback returns true (if User have privilege for that row), otherwise false.

 

Where _cbHavePriv( $row ) is defined

    public function _cbHavePriv( $row ){
      $user_id = $this->sess_info['user_id'];

      return( $user_id == $row->USER_ID );
    } // _cbHavePriv  

This required extending libraries/grocery_crud.php (actually, I just added it, . . . for now)

 

in class grocery_CRUD

/* in the callbacks secton */
 protected $callback_before_upload     = null;
 protected $callback_after_upload        = null;
+  protected $callback_can_edit              = null; 
+  protected $callback_can_delete           = null; 

/* a little bit farther, after callback_after_upload */
 /**                                                                                                                                                                                           
  *                                                                                                                                                                                                 
  * A callback triggered before displaying edit_action (per row)                                                                                                                               
  * @param mixed $callback                                                                                                                                                                          
  * @return grocery_CRUD                                                                                                                                                                            
  */
public function callback_can_edit($callback = null)
{
      $this->callback_can_edit = $callback;
      return $this;
 }
/**                                                                                                                                                                                           
 *                                                                                                                                                                                                 
 * A callback triggered before displaying delete_action (per row)                                                                                                                             
 * @param mixed $callback                                                                                                                                                                          
 * @return grocery_CRUD                                                                                                                                                                            
 */
public function callback_can_delete($callback = null)
{
      $this->callback_can_delete = $callback;
      return $this;
}

 

Then in class grocery_CRUD_Layout, function showList($ajax = false, $state_info = null)

replace the "foreach($data->list as $num_row => $row){" loop with

 

if( $this->callback_can_edit != null || $this->callback_can_delete != null ){                                                                                                                     
  foreach( $data->list as $num_row => $row ){
    if( $this->callback_can_edit != null ){
      $cb_return = call_user_func($this->callback_can_edit, $row);
      $data->list[$num_row]->edit_url = ( $cb_return === false ) ? null : $data->edit_url.'/'.$row->{$data->primary_key};
    }
    if( $this->callback_can_delete != null ){
      $cb_return = call_user_func($this->callback_can_delete, $row);
      $data->list[$num_row]->delete_url = ( $cb_return === false ) ? null : $data->delete_url.'/'.$row->{$data->primary_key};
    }
  }
} else {
  foreach($data->list as $num_row => $row){
    $data->list[$num_row]->edit_url   = $data->edit_url.'/'.$row->{$data->primary_key};
    $data->list[$num_row]->delete_url = $data->delete_url.'/'.$row->{$data->primary_key};
  }
}

finally, in assets/grocery_crud/themes/flexigrid/view/list.php

after the "<div class='tools'>" line, and the != null bits

 

                                <div class='tools'>
                        <?php if(!$unset_delete && $row->delete_url != null ){?>
                        <a href='<?php echo $row->delete_url?>' title='<?php echo $this->l('list_delete')?> <?php echo $subject?>' class="delete-row" >
                             <span class='delete-icon'></span>
                        </a>
                    <?php }?>
                    <?php if(!$unset_edit && $row->edit_url != null ){?>
                        <a href='<?php echo $row->edit_url?>' title='<?php echo $this->l('list_edit')?> <?php echo $subject?>' class="edit_button">
                             <span class='edit-icon'></span></a>

davidoster
  • profile picture
  • Member

Posted 25 March 2013 - 14:00 PM

Why do you use the unset_add and unset_delete functions via your controller depending on the logged in user?


meyercr
  • profile picture
  • Member

Posted 26 March 2013 - 03:52 AM

This is a good suggestion, except that the determination of (add / delete) is per row of the table (list) being displayed.

 

The table list is displaying a list of projects, each of which may be viewable, but not editable by the current logged in user, or vice versa.

 

I hope that makes it clearer.


davidoster
  • profile picture
  • Member

Posted 26 March 2013 - 07:15 AM

Step 1. You unset the operations you don't want to be shown.

Step 2. you use this approach, http://www.grocerycrud.com/documentation/options_functions/add_action

 

If you check closely the 2nd add_action which generates the button photos via the callback takes as a parameter the row->country which is a field of the displayed table.

 

This way you specialize your callback function by certain row data.

Just use on your callback row->field_name, where field_name is a field name that you can use the row data it holds to customize the output of the button!

 

Is it clear now?


wonder
  • profile picture
  • Member

Posted 07 April 2013 - 09:57 AM

Hi there,

I'm trying to hide a row button but struggling with my conditional statement.

I want to hide a button when the row 'con_work_id' is empty.

I've done an add action;

 

// Add action
    $crud->add_action('Work Info', '', '','ui-icon-plus',array($this,'company_detail'));
 

...and later declared the function which doesn't work;

// Function
function company_detail($primary_key , $row)
if('con_work_id' !='')

{
    return site_url('wow_contacts/work').('/').$row->con_work_id;
}

 

 

I'm just starting out, so excuse what is probably a really basic detail.

 

Many thanks,

Wonder


davidoster
  • profile picture
  • Member

Posted 07 April 2013 - 17:54 PM

This is the correct function,

 

function company_detail($primary_key , $row)
if(row->con_work_id !='')

{
    return site_url('wow_contacts/work').('/').$row->con_work_id;
}

 

I suspect you need to put on this function an else part.


wonder
  • profile picture
  • Member

Posted 07 April 2013 - 18:37 PM

I guess this is where I'm struggling.

On the else part how do I hide the button from the row?


davidoster
  • profile picture
  • Member

Posted 08 April 2013 - 07:52 AM

function company_detail($primary_key , $row)
if(row->con_work_id !='')

{
    return site_url('wow_contacts/work').('/').$row->con_work_id;
}
else
{
  // this code here runs only if row->con_work_id == '' equals to empty
  // so put your code
  
  // CAUTION... is row->con_work_id a string???

  // maybe on the if statement you need to say... 
  // if(row->con_work_id == null)
}

 

 

 

I suggest you go ahead and learn pretty good PHP before trying to tackle a project that you might not be able to handle.


tiagows
  • profile picture
  • Member

Posted 10 April 2013 - 04:45 AM

@meyercr

I had a similar issue here and I liked your solution.

I just changed your code a little bit at the class grocery_CRUD_Layout, function showList($ajax = false, $state_info = null) in order to allow use just one of the two callbacks in a grid. Code below:

		  foreach($data->list as $num_row => $row){
		  	if( $this->callback_can_edit != null ){
		      	$cb_return = call_user_func($this->callback_can_edit, $row);
		      	$data->list[$num_row]->edit_url = ( $cb_return === false ) ? null : $data->edit_url.'/'.$row->{$data->primary_key};
		    } else {
		    	$data->list[$num_row]->edit_url   = $data->edit_url.'/'.$row->{$data->primary_key};
		    }
		  	if( $this->callback_can_delete != null ){
			    $cb_return = call_user_func($this->callback_can_delete, $row);
			    $data->list[$num_row]->delete_url = ( $cb_return === false ) ? null : $data->delete_url.'/'.$row->{$data->primary_key};
		    } else {
		    	$data->list[$num_row]->delete_url = $data->delete_url.'/'.$row->{$data->primary_key};
		    }
		  }

 

And I add a callback_before_delete in order to prevent the user delete a row typing the url directly.

$crud->callback_before_delete(array($this,'_cb_c_before_delete'));

 

function _cb_c_before_delete($primary_key)
    {
        if ($primary_key == 3)  {
            return false;
        }
        return true;
    }    

That prevent the user delete the row_id=3, but on Internet Explorer it behaves weird and doesn't allow delete any row! Someone could help me on that?

And I'm still struggling in order to prevent the update.

 

 

@davidoster

I tried your solution to unset the operations and add an action, but on this way all rows were showing the images for delete and edit, and worse of all when clicking on one of them the action couldn't be realized just because they were unset.

Can you post a code showing how to hide the button based on a row value.

 

Thank you.


davidoster
  • profile picture
  • Member

Posted 10 April 2013 - 09:15 AM

[member=tiagows] when you unset_add and/or unset_edit the delete and add buttons should not be displayed at all!

maybe there is something wrong with your code or javascript?

maybe the changes you made on the library itself altered something else also?

For example, here the unset_add, unset_delete made the add and delete buttons disappear correctly!

 

Similarly here there are many different add_actions that work ok!

 

So review your code and any changes you have made to the lib.


tiagows
  • profile picture
  • Member

Posted 10 April 2013 - 19:40 PM

The code is ok. When I unset_delete or unset_edit all the buttons go away correctly.

 

But my goal is show them for some of the rows, not all nor none. And I must guarantee that the user can't access a forbidden action typing the url directly, for example, delete a row that is not showing the delete button.

 

The aproach of meyercr works great for display or not the buttons for edit and delete, but don't prevent the direct access, as I try to explain below.
Here is a flexigrid picture where for the user_id=1 the buttons edit and delete don't exist using his callbacks can_edit and can_delete, so a commom user won't edit or delete it.

 

[attachment=505:flexigrid.JPG]

 

But an user with more experience could type directly at the browser: "{base_url}/main/user/edit/1" and then he could edit the user_id=1. So, I'm using the callbacks of meyercr in order to show the buttons just for the allowed operations, it looks great, and I'm using an extra code for prevent the actions forbidden.

 

I changed a little bit my delete prevent function and it's working great on IE also.

    function _callback_c_before_delete($primary_key, $post_array)
    {
        if ($primary_key == 1)  {
            return false;
        }
        return $post_array;
    }  

Of course the if statement is just an example, and in the real world it will be more complex.

Now I'm trying to make it work for the edit stuff with the callback_before_update and callback_update, but didn't get it yet. If someone knows how I'll appreciate the help.


tiagows
  • profile picture
  • Member

Posted 10 April 2013 - 21:05 PM

I found a way to prevent the unwanted edition. I check if the state is 'edit' and if so I redirect the user.

	if ($crud->getState() == 'edit') {
            $state_info  = $crud->getStateInfo();
            $primary_key = $state_info->primary_key;
            if ($primary_key == 1) {
                redirect('controller/function');
            }
        }
    $crud->callback_before_delete(array($this,'_callback_c_before_delete'));
    $crud->set_lang_string('delete_error_message', 'You cannot delete this user!');
    
    $output = $crud->render();
    $this->_example_output($output);

vecais
  • profile picture
  • Member

Posted 20 November 2013 - 17:10 PM

Hi everyone, 

 

I tested the meyercr's code.

 

I think that these modifications is complete,

for example if you only disable edit with the callback function of meyercr, you have an error, because the $delete_url isn´t defined.

               if( $this->callback_can_edit != null || $this->callback_can_delete != null )
                {                                                                                                                     
                  foreach( $data->list as $num_row => $row ){                      
                    if( $this->callback_can_edit != null ){
                      $cb_return = call_user_func($this->callback_can_edit, $row);
                      $data->list[$num_row]->edit_url = ( $cb_return === false ) ? null : $data->edit_url.'/'.$row->{$data->primary_key};
                    }
                    //Enable edit
                    else
                    {
                      $data->list[$num_row]->edit_url   = $data->edit_url.'/'.$row->{$data->primary_key};   
                    }
                    //
                    if( $this->callback_can_delete != null ){
                      $cb_return = call_user_func($this->callback_can_delete, $row);
                      $data->list[$num_row]->delete_url = ( $cb_return === false ) ? null : $data->delete_url.'/'.$row- {$data->primary_key};
                    }
                    //Enable delete
                    else
                    {
                     $data->list[$num_row]->delete_url = $data->delete_url.'/'.$row->{$data->primary_key};   
                    }
                    //
 
                   //Enable read action
                    $data->list[$num_row]->read_url = $data->read_url.'/'.$row->{$data->primary_key};
                   // 
                  }
                } else {
                  foreach($data->list as $num_row => $row){
                    $data->list[$num_row]->edit_url   = $data->edit_url.'/'.$row->{$data->primary_key};
                    $data->list[$num_row]->delete_url = $data->delete_url.'/'.$row->{$data->primary_key};
                    $data->list[$num_row]->read_url = $data->read_url.'/'.$row->{$data->primary_key};
                  }
                }

Regards,