Redirect user to the second last page in CakePHP - cakephp

I have a model class Event which has the following actions in question: view and delete.
The deletion can only happen from the view action. Getting to the view action is possible from two places that are:
events/dashboard
and
calendar/view_calendar
the latter takes three parameters: user_id, month and year so that would for example be
calendar/view_calendar/120/5/2014
So depending on which action user got to for example events/view/1400, he has to be redirected accordingly.
The referer does not work as it redirects to the events/view with the id of event which has already been deleted.
Any help or guidance is much appreciated.

Put a second Parameter to the view, like
events/view/1400/0
for dashboard
and
events/view/1400/1
for view_calendar
and pass these params to your delete action, like
events/delete/1400/1
In your delete function you can you use the usual redirect:
if($secondParam == 1) {
$this->redirect(array('action' => 'view_calendar'));
} else {
if($secondParam == 0) {
$this->redirect(array('action' => 'dashboard'));
}
}

You can save somewhere the information about the referrer when you land in events/view and the pass it to events/delete.
You can use a named parameter or a query string so your link to the delete action becomes appear something like
events/delete/1400/referrer:dashboard
or
events/delete/1400/referrer:view_calendar
or
events/delete/1400/?referrer=dashboard

Related

CakePHP 2.0 Accessing model field values for view/controller comparisons - Only letting users edit/delete their own posted items

I am fairly new to CakePHP, I am trying to only allow those users who created an event to be able to edit or delete an event, so I am comparing the current user id, with the 'user_id' field of the event the current event (saved when a user creates an event). Any help would be appreciated thanks, my code(Andrew Perk) is as follows:
public function isAuthorized($user) {
$this->loadModel('User');
if ($user['role'] == 'admin') {
return true;
}
if (in_array($this->action, array('edit', 'delete'))) {
if ($user['id'] != $this->request->data['Event']['user_id']) { ///THIS IS THE LINE I FEEL IS WRONG - PLEASE ADVISE
//echo debug($event['user_id']);
//$this->Session->setFlash(__('You are not allowed to edit someones event'));
return false;
}
}
return true;
}
There are a few ways you can accomplish this. The one I have found that usually works best is to put a callback in the model that will set the user_id for the record you are trying to modify. Then it doesn't have to get all mixed up in controller everywhere you are trying to CRUD a record.
You can read more about limiting user data here: http://blogchuck.com/2010/06/limit-data-by-user-with-cakephp/
This will also apply to deleting data.
Hope it helps. Happy coding!

call action from action in one controller cakephp like controller/action/action

i have a controller called "Movies" so the link is "localhost/Movies" and have some actions in this controller like "localhost/Movies/view/[id]" , "localhost/Movies/view/category/[id]" if i want to make a path by the category name and sub category name like "localhost/Movies/English/new" .
how can i do something like this in cakephp 2. my project now like "localhost/English/new" but i want to put Movies in this path, to make it more fixable, if i want to make a new category just add a column in my database .
thanks
If i understand, maybe by creating a custom route for your action:
In app/config/routes.php:
Router::connect('/movies/:category/:subcategory', array('controller'=>'movies','action' => 'index'));
And you can retrieve the value in your controller with:
echo $this->params['category'];
echo $this->params['subcategory'];
You can also read about it in the cookbook http://book.cakephp.org/1.3/view/945/Routes-Configuration
The default routing in CakePHP is as follows:
mydomain/controller/action/param1/param2/param3/param4/...
If you want to add filter options to an action, just add optional parameters to the action.
function index($category = null, $subcategory = null) {
if(isset($subcategory)){
//will execute if you pass both arguments
}else if(isset($category)){
//will execute if you pass one argument
}else{
//will execute if you pass no arguments
}
}
EDIT
In this case, $category is param1, and $subcategory is param2. The overloaded function can receive either 1, 2, or no arguments. If this is in, for example, the ObjectsController, all these are valid URLs:
localhost/objects/index/ //$category==null, $subcategory==null
localhost/objects/index/foods/ //$category=='foods', $subcategory==null
localhost/objects/index/foods/green/ //$category=='foods', $subcategory=='green'
This allows you to control many options in the same action.

Receive model data inside a CakePHP model callback function

I try to use existing model data inside a models callback function in CakePHP 2.1 but can't get it working.
What I do is I try to get a users role in the beforeValidate() callback and check if it's empty. If yes, I'll set it. Normally I do it like this, and for the first creation of the record it works pretty well.
if (empty($this->data[$this->alias]['role']))
$this->data[$this->alias]['role'] = 'user';
The problem is, every time an existing record (user) gets updated, the role will be set again.
Question: So, how do I check if the field role is already set in the record data, not the post data (seems like $this->data[$this->alias] only contains POST data)?
There are three solutions to this problem as I can see it.
Set a default value in the database column (easiest, best?)
Add role to your inputs everytime.
Lookup the user and add a role if it's missing
The first two options seem obvious, so I'll just illustrate the last.
public function beforeValidate() {
if (!empty($this->id) {
$this->data[$this->alias][$this->primaryKey] = $this->id;
}
if (!empty($this->data[$this->alias][$this->primaryKey])) {
// user exists, check their data
$id = $this->data[$this->alias][$this->primaryKey];
$user = $this->find('first', array(
'conditions' => array($this->primaryKey => $id)
));
$this->data[$this->alias]['role'] = $user[$this->alias]['role'];
}
if (empty($this->data[$this->alias]['role'])) {
// new user but missing a role
$this->data[$this->alias]['role'] = 'user';
}
return true;
}
This callback will check if an ID was passed, and if so it will look up the user and populate the role field. Then, it checks for an empty role and fills it with the default if necessary. Obviously he more code you have, the more possibilities for bugs, so I suggest the first option for default column values.
try:
if (empty($this->data[$this->alias]['role']) && empty($this->role)) {
$this->data[$this->alias]['role'] = 'user';
}

CakePHP user session not updating but database yes

I'm developing with cakePhP and I have the following problem:
When a user logs in with his name and password to the account system that I've created, he can save items (images) as favorites. This is saved in a text field into the database. What is saved is the image ID.
The saving process works perfectly, the user clicks on the images and they're added to that field (it actually saves all the IDs as a text array that I process later).
The problem comes when removing images. When the user does it (I'll post the code below), the images is removed correctly from the database (I go to PHP MyAdmin and I see it). This means that the array that holds the favorite images IDs is updated instantly. However, when I reload that array from the website, it hasn't been updated. It's like it's stored in the caché or something. Then, if the user logs out and logs in again, then he can see the correct one. The thing is that I have other things in my website that work in a similar way and they all get updated instantly, so I can't see why this doesn't.
This is the code that I use to remove the ID from the database:
function remove_favorite($pictureID) {
$this->User->id = $this->Auth->User('id'); //We get the ID of the current user
$favoritesArray = $this->User->deleteFavoritePicture($this->User->id, $pictureID); //This function retrieves the array (string) of pictures from the user's table, and deletes all the images with the ID passed as parameter, returning the updated array (string)
$fields = array('images_favorites' => $favoritesArray, 'modified' => true); //We indicate the field that we're going to update in the users table
//We save the new string that doesn't contain the deleted image anymore
if($this->User->save($fields, false, array('images_favorites'))) {
$this->Session->setFlash(__('The image has been removed from your favorites', true));
} else {
$this->Session->setFlash(__('Error removing image from favorites, please try again', true));
}
$this->redirect(array('action' => 'manage_favorites',$this->User->id));
}
This is how the deleteFavoritePicture function looks like:
function deleteFavoritePicture($userID, $pictureID) {
$userInfo = $this->find("id = $userID");
$favoritePicturesString = $userInfo['User']['images_favorites'];
$favoritePicturesArray = explode(",", $favoritePicturesString); //Array
$i = 0;
while ($i < count($favoritePicturesArray)) {
//We remove from the array the images which ID is the one we receive to delete
if ($favoritePicturesArray[$i] == $pictureID) unset($favoritePicturesArray[$i]);
$i++;
}
$favoritePicturesString = implode(",", $favoritePicturesArray); //String
return ($favoritePicturesString);
}
That's it. Does anyone now what can be going on? Thanks so much in advance for any clue!
EDIT
Ok, I think I found something that may give a clue of what's going on here:
This is the code for the manage_favorites action:
function manage_favorites($id) {
//$user = $this->User->find("id = $id");
$user = $this->Auth->user();
$this->set('user', $user);
}
That is the action that is called for the page when a user wants to modify his favorites. The same action is called once the user removes a favorite. Here's the thing:
If I use the $id parameter in the manage_favorites function and the $user = $this->User->find("id = $id"); line (the one quoted now), then the problem does not exist! This is how I used to have it. HOWEVER, I had to change it because it was a big security flaw, since the user id ($id) was a visible parameter who anyone could change, and then access other users accounts. What I did was changing the way I obtain the user array of favorite images, using the following line: $user = $this->Auth->user();. This is how I have it now (well, and also without the $id parameter in the function header), so the user information (including the favorites array) comes from the Auth component, instead directly from the database.
So, the problem is clear: when the user deletes a favorite, it's doing it on the array in the database. WHen I show the result of that operation, the array I'm retrieving is not the one in the DB, it's the one in the session. That's why it's not showing the changes.
How can I avoid this without using a non-secure method like the one I had before?
When you save, the array passed to the save method of the model should look like this:
[User] => array(
[field] => value,
[field2] => value2,
...
)
In your example, you clearly haven't added the [User] key.
Also, is your modified field actually the default Cake modified field? That is, the DATETIME field which changes to the current time when the row is updated?
Lastly, maybe you have debugging set to 2 in config.php. try changing this to 0 (as in production) and see if caching persists.
Hope some of the points I have mentioned above will solve your problem. Please let me know!
There could be two things wrong with this.
What does your deleteFavoritePicture method look like? There could be something being done wrong there.
You're passing false as the second parameter to the User::save method, which means that you don't want to validate. Unless there is a SQL error, then this will return true even if it doesn't validate properly, I believe. Try changing this false to true and see if your results differ.

Filtering data using ajax observefield

I ve tried to implemented filtering data (list base on selected category) using dropdown with observefield and ajax pagination. I use session to remember selected category in order to keep pagination.
Here is my code (Cakephp 1.2)
In view :
echo $form->select('Category.id', $categories, null, array('id' => 'categories'),'Filter by Categories')
echo $ajax->observeField('categories' ,array('url' =>'update_category','update' => 'collectionDiv'));
In Controller:
if(!empty($this->data['Category']['id']))
{
$cat_id=$this->data['Category']['id'];
$filters=array('Collection.category_id' => $cat_id);
$this->set('collections', $this->paginate('Collection', $filters));
$this->Session->write($this->name.'.$cat_id', $category_id);
}
else
{
$cat_id=$this->Session->read($this->name.'.cat_id');
$filters=array('Collection.category_id' => $cat_id);
$this->set('collections', $this->paginate('Collection'));
}
The filter work as I wanted but the problem is when I select empty value('Filter by Category) it still remember last category session so I can't back to the default list (All record list without filter).
I've tried to make some condition but still not success. Is there another way? Please I appreciate your help. thank
hermawan
Perhaps I don't understand the question, but it looks to me like it might be worth changing:
else
{
$cat_id=$this->Session->read($this->name.'.cat_id');
$filters=array('Collection.category_id' => $cat_id);
$this->set('collections', $this->paginate('Collection'));
}
to:
else
{
$this->set('collections', $this->paginate('Collection',array()));
}
In effect your code appears to be doing this anyway. Check what the URL is at the top of the browser window after it has returned. Does it still contain pagination directives from the previous query?
You might want to review http://book.cakephp.org/view/167/AJAX-Pagination and make sure you've 'ticked all the boxes'.
I got it, It work as I hope now. I my self explain the condition and solution.
When I select category from combobox, then it render the page the code is :
If ($this->data['Category']['id']) {
$cat_id=$this->data['Category']['id'];
$this->Session->write($this->name.'.category_id', $category_id);
// I will use this session next when I click page number
$filters=array('Collection.art_type_id' => $category_id);
$this->set('collections', $this->paginate('Collection', $filters));
}else{
//if clik page number, next or whatever, $this->data['Category']['id'] will empty so
// use session to remember the category so the page will display next page or prev
// page with the proper category, But the problem is, when I set category fillter to
// "All Category" it will dislpay last category taked from the session. To prevent it
// I used $this->passedArgs['page']. When I clik the page paginator it will return
// current number page, but it will be empty if we click dropdown.
if (!empty($this->passedArgs['page']) {
$cat_id=$this->Session->read($this->name.'.category_id');
$filters=array('Collection.category_id' => $cat_id);
$this->set('collections', $this->paginate('Collection',$filters));
}else{
$this->set('collections', $this->paginate('Collection'));
}
}
From this case, I think that observefield will not send passedArg as we get from url such from ajax link or html->link. I hope this will usefull to anybody

Resources