CakePHP Write URL path from initial search() action pagination array - arrays

I've hit a roadblock and cannot for the life of me get over.
I have a search() action which is working as expected.
From that function, I pass my pagination value to the results page and I get an array like so:
Array
(
[controller] => plans
[action] => search
[0] => 35
[1] => 0
[2] => 0
[3] => 1
[4] => 97389
)
ALL search results display correct (and array data is correct). BUT my url ONLY displays the Model and Action value when the initial results are displayed like so:
...plans/search
And if I do a paginator() *sort()* (in my header fields) or Next >> my pagination array prints to the url like so:
...plans/search/45/0/0/0/97389/page:1/sort:monthly_cost/direction:desc
Everything is working as expected BUT I need my initial search to display the url path as it does when paginator() or sort() is used.
I've tried imploding the array and tacking it onto the url (no dice).
I've tried to rewrite the url with the array (but this conflicts with the pagination)..
I've tried a bucket load of get and post ideas.. (no dice)..
Am I overlooking something VERY simple here? Someone please send any ideas you might have. This is kicking my butt!

I finally solved this:
In my search function, this is what I did:
if($this->RequestHandler->isPost()) {
$this->Session->write('search_form_sess', $this->data);
$initial_url = $ApplicantAge . '/' . $SpouseAge . '/' . $NumberChildren . '/' . $Vision . '/' . $Zip;
$this->redirect(array('action' => 'search', $initial_url));
exit();
}
As you can see I am also capturing the search form session data to pass to the search form to hold the search values in the inputs.

Related

Cakephp-2.5 next navigation url without html code

How can I get next navigation url without html code ?
$this->Paginator->next();
//output
Next
I just need url only.
The paginator helper itself doesn't support that, the least HTML'd return value (tag => false) is a simple anchor element, so you'll have to build the URL on your own, which is pretty simple tough.
What you need is the current page number, this can be retrieved via PaginatorHelper::params(), the page key in the returned array holds the current page.
All you have to do then is add 1 to it, and pass a URL array with the key page and the new page number as its value to Router::url() and you'll get the URL for the next page:
$params = $this->Paginator->params();
$url = array(
'page' => $params['page'] + 1
);
echo Router::url($url);
ps. you might want to check whether there is actually a next page using PaginatorHelper::hasNext()
if($this->Paginator->hasNext())
{
// ...
}

Paginator Not Found when page number specified

I manually set the CakePHP Pagination values in my Usergals Controller like so, so as to Paginate a related Model (TreasuresUsergal) on the view of Usergal. Here is a simplified snippet from the UsergalController:
public function view($id = null) {
$this->loadModel('TreasuresUsergal');
$options['joins'] = array(
array('table' => 'treasures',
'alias' => 'Treasure2',
'type' => 'LEFT',
'conditions' => array(
'Treasure2.id = TreasuresUsergal.treasure_id',
)
)
);
$options['conditions']=array('TreasuresUsergal.usergal_id'=>$id);
$options['fields']=array('Treasure2.*','TreasuresUsergal.ord','TreasuresUsergal.comments');
$options['order']=array('TreasuresUsergal.ord'=>'asc');
$options['limit']=$limit;
$this->Paginator->settings = $options;
$treasures=$this->Paginator->paginate('TreasuresUsergal');
$this->set('treasures',$treasures);
}
So in the above example, $id is the value passed to the view function from the URL. There is a live example of this here:
http://collections.centerofthewest.org/usergals/view/20
As you can see, it works just fine for a single page. However, today I tested the Paginator in the view and discovered the "next" button does not work. The Counter, sorting, and Page numbers all load correctly - but anytime the actual named parameter "page:n" is passed (when n is greater than 1) I get a Not Found page with the following error:
Not Found
Error: The requested address '/usergals/view/20/page:2?url=%2Fusergals%2Fview%2F20' was not found on this server.
I must be missing something simple - I have experimented with the routes a little, but haven't been able to figure it out. Or perhaps I am missing some Paginator options? Or does it think its OutOfBounds when its not?
UPDATE / WORKAROUND
After some messing around, I have devised this workaround. Not as nice as I'd like, but here is the basic idea (error handling, etc can be added)
First, I added a check in beforeFilter to see if page paramter was set. If so, I change it to 'p' parameter and redirect.
I did this here because otherwise I had problems with the Not Found exception (see notes at bottom). So, in beforeFilter:
if (isset($this->params['named']['page'])){
$newurl=$this->params['named'];
$pg=$newurl['page'];
unset($newurl['page']);
$newurl['p']=$pg;
$this->redirect(array('action' => 'view/'.$this->params['pass'][0])+$newurl);
}
Then, in the 'view' function of the same controller, I added this along with the other Paginator options:
if (isset($this->params['named']['p'])) $options['page']=$this->params['named']['p'];
With this, the standard Paginator behavior seems to work fine in the view. Prev, next, etc.
If anyone has a better suggestion, I would love to hear it. I don't like the idea of having to redirect, but it works for now.
It's worth noting that adding this code (even just to experiment) - caused all of my pagination counts to stop working. The query in debug was correct, but the displayed counts were wrong:
try {
$this->Paginator->paginate();
} catch (NotFoundException $e) {
}

Dumping a drupal 7 render array to file

I'm having a hard time outputting some array data to an XML file. Here's the workflow:
Get all relevant data (in this case, a collection of videos and the necessary taxonomy) from the DB.
Loop each returned object, cleaning it up a bit (field combinations, etc).
Loop each returned object, returning an XML node by use of a template file (templates/module_name_xml_entity.tpl.php).
Put all the XML nodes into a wrapper XML template (templates/module_name_xml_wrapper.tpl.php).
Save the wrapper (now including the repeated nodes) into a file on the filesystem.
I have been able to complete this workflow if I manually write XML inline (eg: $xml .= ' ' . $data['field'] . '';
That's not optimal however, and I've been asked to use render arrays instead (and to keep my template files within the module).
So, #'s 1, 2, 5 I can figure out (since saving a file is the same). It's #3 that is the real bugger.
My code:
The dump from the db query results in an array of video objects (title, thumbnail, tags, etc). I convert that to the following:
Array (
[#template] => module_name_xml_entry,
[#video] => stdClass Object (
[title], [thumbnail]....
),
[#theme] => module_name_xml_entry,
)...
Now here's something interesting: if I dd() the array (there's 990 of them), I see that "#children" and "#printed" has been added automagically, therefore I assume I'm working with a real render array.
I then try every darn way I can think of to convert this array into XML. I've tried $xmlOut .= render($theStuffAbove), drupal_render($youguessedit), please_lord_make_it_go($facepalm)... no avail.
What I get out is either blank (nothing is in $xmlOut) or the array itself.
Again, I can loop my DB results, convert the result into XML manually (string building mess) and save all that out just fine. It's the using of render arrays that baffles me. Reading "TDGD7" hasn't helped (there's only a few short pages out of 1047 on render arrays), and I'm just not understanding how render arrays can be "rendered."
Update:
I forgot to mention I do have a module_name_theme(...) function setup:
$items = array();
$items['module_name_admin_settings_form'] = array(...);
$items['module_name_xml_wrapper'] = array(
'variables' => array('videos' => NULL)),
'template' => 'templates/module_name_xml_wrapper',
);
$items['module_name_xml_entity'] = array(
'variables' => array('video' => array()),
'template' => 'templates/module_name_xml_entity',
);
return $items;
Fixed
Ok, so this is odd (swear I'd done this before).
Changed template filenames to use dashes instead of underscores (eg: 'templates/module_name_xml_entry.tpl.php -> module-name-xml-entry.tpl.php)
Changed reference in the hook_theme() to use the dashed names instead
Inside my functions, I used a $variables = array('video' => $video);
I called $output[] = theme('module_name_xml_entry', $variables);
I used $output in my wrapper (module_name_xml_wrapper) to save to the filesystem.
So the long and short: it looks like cleaning up the theme() function and my hook_theme() made the output work finally.

Pagination links breaking search results coming from post data cakephp

When I've Search my listing i'm getting some results with pagination, but when i go for second page my search is
breaking as it was a get request where i'm getting the search results via post method.
Note: For getting search results I don't want to submit the form via get request (i.e. Query string params) and also don't want to store the form data in session
Is there any way to get the results which satisfy the above conditions ?
You want to implement the PRG Pattern.
Post/Redirect/Get (PRG) is a web development design pattern that
prevents some duplicate form submissions, creating a more intuitive
interface for user agents (users). PRG implements bookmarks and the
refresh button in a predictable way that does not create duplicate
form submissions.
The CakeDC Search plugin makes that pretty easy to do in CakePHP.
It would be very hard to do it using only "POST" calls. You'll need to transfor your POST into a GET call.
Check this post i made or clone it from github
Hope this helps
EDIT:
Using my git repo. If you want url querystrings instead of named parameters:
in this line, instead of the foreach build the querystring and pass it to the redirect
in this line, get the parameters from the query string ($GET)
and in this line add page, sort and direction to this->paginate
I haven't tested it, but it should be something like that
We can do it with a patch.
In Views :
create search form :
$this->Form->create('Search', array('url' => array('controller' => 'controller', 'action' => 'index', substr(time(), 2,rand(1, 7) ))) );
Note : A random number appended at the end of the form action. This will let us know when to clear session.
in Controller :
public function index( $search = null)
{
$conditions = array(1 => 1);
if( !empty($this->data['Search']['keyword']) && $search)
{
$conditions = array('Model.field like' => $this->data['Search']['keyword'] . '%');
// store search array in session
$this->Session->write('conditions', $this->data['Search']);
}
if ($search)
{
$this->request->data['Search'] = $this->Session->read('conditions');
$conditions = array('Model.field like' => $this->data['Search']['keyword'] . '%');
}
else
{
$conditions = array(1 => 1);
$this->Session->delete('conditions');
}
$this->paginate= array('limit'=> 10, 'conditions' => $conditions);
$lists = $this->Paginate('Model');
}
Hope you understand the logic behind.

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.

Resources