CakePHP How to Persist Search Querystring to Subsequent Paginator Pages - php

I had a search page that filtered correctly, but when it paginated you would lose the data since I was POSTing it. So I switched it to a GET, but I can't figure out how to add the http_build_query( $params ) that I passed back to the paginator.
I've tried setting query params in the paginator url in options, but with no luck and the API doesn't mention adding the query params.
How do I set the search results query params so the different pages know what they were being filtered on? So a search on name=steve and company=SomeCompany is maintained through page 2, 3, 4, with 10 results each, and doesn't reset to show all non-filtered 100 results.
Simple Example Pagination in Controller
$this->paginate = [
'limit' => 5,
'order' => [ 'CollectionAgencyAgent.id' => 'desc' ]
];
return $this->paginate( $this->CollectionAgencyAgent, $conditions );
VIEW with Pagination
<ul class="pagination <?php echo $class ?>">
<?php
$this->Paginator->options( [
'url' => [
'controller' => ''
]
] );
?>
<?php echo $this->Paginator->prev( __( '« Previous' ), [
'escape' => false,
'tag' => 'li',
'class' => 'arrow',
'disabledTag' => 'a'
] ); ?>
<?php echo $this->Paginator->numbers( [
'separator' => '',
'tag' => 'li',
'currentTag' => 'a'
] ); ?>
<?php echo $this->Paginator->next( __( 'Next »' ), [
'escape' => false,
'tag' => 'li',
'class' => 'arrow',
'disabledTag' => 'a'
] ); ?>
</ul>

The paginator class automatically merges the current request parameters:
public function beforeRender($viewFile) {
$this->options['url'] = array_merge($this->request->params['pass'], $this->request->params['named']);
if (!empty($this->request->query)) {
$this->options['url']['?'] = $this->request->query;
}
parent::beforeRender($viewFile);
}
So the short answer is to do nothing, and that'll just work.
The reason it doesn't work with the code in the question is that this call:
$this->Paginator->options( [
'url' => [
'controller' => ''
]
] );
Which will wipe out the Paginator's run time url options. So, to prevent the problem in the question - just delete that call (and then, probably fix the routing problem which prompted you to add it =)).

Related

Unable to access comment meta?

The Setup
Using the Reviews extension for WP Job Manager, I have comments with the meta field review_average which is an average of `review_stars. I'm customizing the WP REST API so I can read and write comments remotely via the mobile app I'm building.
I've exposed these fields with
register_meta( 'comment', 'review_average', array( 'show_in_rest' => true,
'type' => 'string',
'description' => 'review_average',
'single'=> false));
register_meta( 'comment', 'review_stars', array( 'show_in_rest' => true,
'type' => 'string',
'description' => 'review_stars',
'single'=> false));
which results in this field in the REST API response for comments:
meta: {
review_average: [
"4"
],
review_stars: [
"Array"
]
},
(I can't seem to break down that array, but there's only one stars category so the average is fine)
I've written a create_review function that uses add_comment_meta to write to review_average and review_stars which successfully gives the comment the right stars. Both those meta values are required for it to work.
function create_review($param) {
$id = wp_insert_comment(array('comment_post_ID' => $param['post_id'],
'comment_author' => $param['username'],
'comment_author_email' => $param['email'],
'user_id' => $param['user_id'],
'comment_content' => $param['content']));
if ($id) add_comment_meta($id, 'review_average', $param['rating']);
if ($id) add_comment_meta($id, 'review_stars', array('Your Rating'=>$param['rating']));
return get_comment($id);
}
The Problem
I can't seem to get the ratings meta info into a response for the comments. On my way to writing the "index" function get_comments, I've written the "show" function, get_commment:
function get_review($param) {
$id = $param['id'];
$info = get_comment($id);
$res = array(
'id' => $id,
'author_name' => $info->comment_author,
'author_email' => $info->comment_author_email,
'author_id' => $info->user_id,
'date' => $info->comment_date,
'rating' => $info->review_average
);
return $res;
}
The response has rating: null. Same result with 'rating' => $info->meta->review_average, as well as using _review_average in both those scenarios.
I have another function for my custom posts, which are job_listings that in my app are customers.job_listing has a meta field that shows up in the default REST API response under meta as _job_location, but inside my get_customer function, $res['address'] = $info->_job_location; works just fine!
How do I get the damn rating_average meta!?
Well, 'rating' => get_comment_meta($id) inside my get_review method gives me this:
"rating": {
"review_average": [
"4"
],
"review_stars": [
"a:1:{s:11:\"Your Rating\";s:1:\"4\";}"
]
}
And then
'rating' => get_comment_meta($id)['review_average'][0],
'rating_info' => get_comment_meta($id),
Gives me a nice full
"rating": "4",
"rating_info": {
"review_average": [
"4"
],
"review_stars": [
"a:1:{s:11:\"Your Rating\";s:1:\"4\";}"
]
}
I'm learning php as I go, so I'd love if someone could post a comment about why
get_comment_meta($id)->review_average
returns null but
get_comment_meta($id)['review_average']
works.

How can I make typeahead show database information in yii2?

I want to make search in my project. I use typeahead but it's not working. This is my code:
<?php
echo '<label class="control-label">Select Repository</label>';
$template = '<div><p class="repo-language">{{no_telepon}}</p>' .
'<p class="repo-name">{{nama}}</p>' .
'<p class="repo-description">{{email}}</p></div>';
echo Typeahead::widget([
'name' => 'twitter_oss',
'options' => ['placeholder' => 'Filter as you type ...'],
'dataset' => [
[
'prefetch' => Penerima::find()->all(),
'datumTokenizer' => "Bloodhound.tokenizers.obj.whitespace('value')",
'display' => 'value',
'templates' => [
'notFound' => '<div class="text-danger" style="padding:0 8px">Unable to find repositories for selected query.</div>',
'suggestion' => new JsExpression("Handlebars.compile('{$template}')")
]
]
]
]);
?>
This question was asked long time a go.
I also faced the same problem, but i could figure-out this.
for future reference i add this post.
in your controller
$result = SampleModel::find()
->select('Attribute_name')
->where('name LIKE "%' . $searchParameter .'%"')
->asArray()
->all();
return Json::encode($result);
here you need to get the database value as "associative array", you can get that from using "asArray()".
then as you see return value as Json encode.
in your "View"
<?php
echo Typeahead::widget([
'name' => 'sampleName',
'options' => ['placeholder' => 'Filtering data ...'],
'scrollable' => true,
'pluginOptions' => ['highlight'=>true],
'dataset' => [
[
'remote' => [
'url' => Yii::$app->urlManager->createUrl(['sample/action']) .
'?searchParameter=%QUERY',
'wildcard' => '%QUERY'
],
'datumTokenizer' => "Bloodhound.tokenizers.obj.whitespace('Atribute_name')",
'display' => 'Atribute_name',
'limit' => 10,
],
],
'pluginEvents' => [
'typeahead:select' => 'function(e, s) {
EnableUserDetailsTypeAhead(s);
}',
]
]);
?>
here few things to be consider.
calling to the controller action. you can do that.
Yii::$app->urlManager->createUrl(['sample/action']) .
'?searchParameter=%QUERY',
'wildcard' => '%QUERY'
],
the below lines inside data set must be provide.
'datumTokenizer' => "Bloodhound.tokenizers.obj.whitespace('Atribute_name')",
'display' => 'Atribute_name',
you will get the expected data.
this sample code i have tested and this is working
From the docs:
prefetch: array, configuration for the prefetch options object. Refer documentation for the options you can set for this parameter. The return data must be Json encoded and converted to an associative array of the format [['value' => 'data1'], ['value' => 'data2'],...], where value is the fixed key set in display
You are passing an array of objects instead of an array of key value pairs. You can use asArray to create a list of objects. You will need to change display to the name of the field containing the data:
'prefetch' => Penerima::find()->select('title')->asArray()->all(),

Having values in array that need to be output as string that will be used as code

I'm not sure that i've written something intelligibile in the title either.
I'll try to explain with some codes line. First some information.
I'm working with CakePhP and this problem comes up while creating the arrays for the actions allowed.
Long story short, i'm using an ACL to check whenever a page is loaded if the current user has access to the actions available on that page. This is an example:
//Controller
$role = $this->User->Role;
$role->id = $this->Auth->user('Role.id');
$actionsMenu = array();
$actionsMenu['Files'] = array(
'label' => 'Manage Files',
'controller' => 'project_files',
'action' => 'index',
'parameters' => $id,
'authorized' => $this->Acl->check($role, 'ProjectFiles')
);
$actionsMenu['Groups'] = array(
'label' => 'Manage Groups',
'controller' => 'groups',
'action' => 'index',
'parameters' => $id,
'authorized' => $this->Acl->check($role, 'Groups')
);
In the view I just loop and if the "authorized" is set to true, i'll print the related button.
Now, the problem rise when i've more that one parameter to pass. This is another snippet that follows the one up there:
//Controller [following]
$this->Project->id = $id;
if ($this->Project->field('archived')) {
$actionsMenu['Archiviation'] = array(
'label' => 'Restore',
'controller' => 'projects',
'action' => 'archiviation',
'parameters' => array($id, 0),
'authorized' => $this->Acl->check($role, 'controllers/Projects/archiviation')
);
} else {
$actionsMenu['Archiviation'] = array(
'label' => 'Archive',
'controller' => 'projects',
'action' => 'archiviation',
'parameters' => array($id, 1),
'authorized' => $this->Acl->check($role, 'controllers/Projects/archiviation')
);
}
This is what you can find in the views:
//View
<div class="actions">
<h3><?php echo __('Actions'); ?></h3>
<ul>
<li><?php echo $this->Html->link(__('<- Projects Management'), array('action' => 'index')); ?></li>
<li> </li>
<?php foreach($actionsMenu as $action) : ?>
<?php if($action['authorized']) : ?>
<li><?php echo $this->Html->link(__($action['label']), array('controller' => $action['controller'], 'action' => $action['action'],
is_array($action['parameters']) ? implode(', ', $action['parameters']) : $action['parameters']
)); ?></li>
<?php endif; ?>
<?php endforeach; ?>
</ul>
I thought the array format was the most CakePhP friendly way to pass the values just to discover that in case of multiple parameters, cake tend to prefer an associative array.
The problem here is that CakePhP read that implode as a whole parameter composed by a string.
This is an example:
<!--HTML-->
Restore
What I want to achieve is that the values separated by the comma should be read as different variables.
Honestly I never run in a situation like this and I've neither idea of what to look for on google to find something fitting (being a non-native english speaking isn't helping) so any suggestion is welcome.
Edit1
To clarify, the code listed in the second box (starting with Controller [following]) is the one that is causing problems.
The previous box just build the array with a single parameters that match the simple structure of CakePhP for building link but the second block will need to pass a second parameter. If the values was static one could simply type something like this:
//CakePhP HTML::Link
echo $this->Html->link(
'text of link',
array(
'controller' => 'controller_name',
'action' => 'action_name',
'parameter1', 'parameter2'
));
If I send the list of parameters as string, Cake are considering them a single parameter, reading it like (string)("'parameter1', 'parameter2'").
The same happens with the code i've written above in which i'm converting the array of values to string with implode().
So what I'm asking for, is if there a function, option or practice that I'm missing.
Edit2
As the user user221931 pointed out, the CakePhP function should support multiple parameters as array in the form of array('parameter1', 'parameter2', 'paramenterN').
So i've tried just removing the is_array() check and simply pass the value of $action['parameters']. The view section now look like this:
<?php echo $this->Html->link(__($action['label']), array(
'controller' => $action['controller'],
'action' => $action['action'],
//is_array($action['parameters']) ? implode(', ', $action['parameters']) : $action['parameters']
$action['parameters']
)); ?>
But i've got a warning as follows:
rawurlencode() expects parameter 1 to be string, array given
Going to open the context of the warning, seems like CakePhP is reading the information provided as follows:
$params = array(
'controller' => 'projects',
'action' => 'archiviation',
'plugin' => null,
'pass' => array(
(int) 0 => array(
(int) 0 => '1',
(int) 1 => (int) 1
)
),
'named' => array()
)
Honestly I'm lost here.
I've tried changing the second value of the array to a string too and passing an associative array instead of a numeric just to try something obvious but the error persist and the link comes out truncated without parameters.
The correct format to use Html::link()
echo $this->Html->link(
'text of link',
array(
'controller' => 'users', //Or any controller name
'action' => 'view', //Or any action
1, //Several parameters
'test1', //go here
'test2'
)
);
If you don't know the number of parameters beforehand, you only need to array_merge your fixed array with the array of dynamic parameters.
Assuming $arrayOfParameters holds array('test1', 'test2', 'test3')
$urlArray = array_merge(
array('controller' => 'users', 'action' => 'view'),
$arrayOfParameters
);
echo $this->Html->link('text of link', $urlArray);
Additionally you could implode your array of parameters as a url, i.e:
$urlString = implode('/', $arrayOfParameters); //creates a string 'test1/test2/test3'
echo $this->Html->link('text of link', array(
'controller' => 'users',
'action' => 'view',
$urlString //One parameter that will be looking as many
));

How do I retain query params in the pagination URLs in ZF2?

I am using Zend\Paginator to construct a paginated result set. This works fine, however, after adding a search form, I cannot get the two to play nicely together.
The URL produced by the search form on the page is:
user/index/?searchTerm=hello
How do I amend the Zend paginator configuration so that it retains the searchTerm in the URLs produced?
I was hoping for something like:
user/index/page/4/?searchTerm=hello
What am I missing?
The module config route is defined as follows:
'user' => array(
'type' => 'Zend\Mvc\Router\Http\Segment',
'options' => array(
'route' => '/user[/[:action[/]]][[id/:id]][/[page/:page]]',
'defaults' => array(
'controller' => 'Application\Controller\User',
'action' => 'index',
'id' => null,
),
// the below was added to try and get the searchTerm query to be retained
'may_terminate' => true,
'child_routes' => array(
'searchTerm' => array(
'type' => 'Query',
),
),
),
),
The pagination is constructed using this in the view:
echo $this->paginationControl(
$this->users, 'sliding', array('paginator', 'User'), array('route' => 'user', 'action' => 'index')
);
Pagination template snippet:
<li>
<a href="<?php echo $this->url($this->route, array('action' => $this->action, 'page' => $this->next), true); ?>">
Next »
</a>
</li>
(I was under the impression that passing true as the third parameter to url() would retain the query params.)
I now see what that third parameter to url() is doing. I can simplify the pagination links and remove the 'action' key as follows:
<a href="<?php echo $this->url($this->route, array('page' => $this->next), true); ?>">
The page's action was matched as part of the URL (due to that third param being true) which is why that works. By the same token I can change the route to this:
'route' => '/user[/[:action[/]]][[id/:id]][/[page/:page]][/[search/:search]]',
And then the search will be retained in the pagination links.
If I amend the search form to submit via JavaScript, I can construct the search URL and direct the user to it.
Simple jQuery example for that approach:
$(".search-form").submit(function() {
var baseUrl = $(this).attr('action'),
search = $(this).find('.search').val();
window.location = baseUrl + '/search/' + search;
return false;
});
Another option would be to redirect to the current/route/search/term route in the controller if it receives a searchTerm query.
I'm posting this as an answer but I am open to better solutions.

CakePHP pagination (last param cut)

I have a "little" problem with the Pagination system of CakePHP (1.2). Here is the query:
$this->paginate = array (
'fields' => array (
'Content.slug',
'Content.title',
'Content.resume',
'Content.format',
'Content.image',
'Content.video',
'Criteria.name'
),
'conditions' => $conditions,
'order' => 'Content.created DESC',
'limit' => 10,
'contain' => array (
'Category',
'Criteria',
)
);
$this->set("PRODUCTS", $this->Paginate("Content"));
And the code of view:
<?php $total_pages = (int)$paginator->counter(array('format' => '%pages%')); ?>
<?php if($total_pages > 1){ ?>
<div class="paginar">
<div class="next_pre_arrow">
<?=$paginator->prev("Anterior", array("class" => "pre", "escape" => false))?>
<?=$paginator->next("Siguiente", array("class" => "next", "escape" => false))?>
<div class="pages">
<span>Página</span> <?=$paginator->numbers(array('separator' => ' | '))?>
</div>
</div>
</div>
<?php } ?>
What is the problem? The pagination works OK but with a little problem. In the "next" and "prev" buttons, and in the page numbers, the URL is truncated, deleting the last param, for example:
"http://www.domain.com/controller-name/caction-name/option-1/option-2"
Show paging links with this URL:
"http://www.domain.com/controller-name/caction-name/option-1/page:2"
NOT the correct:
"http://www.domain.com/controller-name/caction-name/option-1/option-2/page:2"
What is the cause of this?
I think you can customize the links that are generated by the Paginator helper using the options() method.
Specifically, you can use $options['url'] to pass a custom URL, as if you were setting parameters of a link() call:
$paginator->options(array(
'url' => array(
'controller' => 'YourController',
'action' => 'your_action'
'param1' => 'value_1',
'param2' => 'value_2',
)));

Categories