I'm trying to get all videos from a DB that contain a keyword, It's an API REST building with Symfony 3. Here is a sample of the URL
http://localhost/Server/symfony/web/app_dev.php/video/search/prueba
Where "prueba" is the keyword that i'm trying to find
Here is the function..
public function searchAction(Request $request, $search = null){
$helper = $this->get("app.helper");
$em = $this->getDoctrine()->getManager();
if($search != null){
$dql = "SELECT v.title FROM BackendBundle:Video v "
. "WHERE v.title LIKE :search OR "
. "v.description LIKE :search ORDER BY v.id DESC";
$query = $em->createQuery($dql)
->setParameter("search", "%search%");
} else {
$dql = "SELECT v FROM BackendBundle:Video v ORDER BY v.id DESC";
$query = $em->createQuery($dql);
}
$page = $request->query->getInt("page", 1);
$paginator = $this->get("knp_paginator");
$items_per_page = 6;
$pagination = $paginator->paginate($query, $page, $items_per_page);
$total_items_count = $pagination->getTotalItemCount();
$data = array(
"status" => "success",
"total_items_count" => $total_items_count,
"page_actual" => $page,
"items_per_page" => $items_per_page,
"total_pages" => ceil($total_items_count/$items_per_page),
"data" => $pagination
);
return $helper->toJson($data);
}
The result should be a JSON with 4 videos.. but I get
{
"status": "success",
"total_items_count": 0,
"page_actual": 1,
"items_per_page": 6,
"total_pages": 0,
"data": []
}
where "data" is an array with the video data
Somebody know what I miss? the dql consult.. it's rigth?
Somebody could tell me what is the mistake? I need a clue.. the dql consult is correct?
I see you use knp_paginator service. Try to get items from paginator like this:
$data = array(
"status" => "success",
"total_items_count" => $total_items_count,
"page_actual" => $page,
"items_per_page" => $items_per_page,
"total_pages" => ceil($total_items_count/$items_per_page),
"data" => $pagination->getItems()
);
Thank you for your replay guys!!
So.. I made a mistake while typing.. and I forgot sign $ before the search word..
thats was the probllem
$query = $em->createQuery($dql)
->setParameter("search", "%search%"); <-- here
Thank you so much!!
Related
I have an user table using DataTables, that will contain more than 200 rows. It's look so fine when I'm using DataTables for default the "pageLength": 10, and this is the table example.
Username | Type | Request |
user01 1 request01
user02 1 request02
user03 2 request03
user04 1 request04
user05 1 request05
user06 1 request06
user07 1 request07
user08 1 request08
user09 1 request09
user10 1 request10
Showing 1 to 10 of 200 entries FirstPrevious123...20NextLast
So, for reducing the loading time, I decide to use "processing": true and "serverSide": true. Then I got some issue with this "serverSide" : true, It's print 200 rows of data in table.
Showing 0 to 0 of 0 entries (filtered from NaN total entries). Then the pagination is still print and after I click the page 2, it's doing nothing.
I wan't the DataTables is getting the 10 data for the first, after pagination 2 is clicked, it will get 10 more and so on.
I'm using CodeIgniter, here is my code :
On my Views + Js :
<select name="task" id="task">
<option value="1">Task 1</option>
<option value="2">Task 2</option>
</select>
<table id="user-request" class="table">
<thead>
<tr>
<th>Username</th>
<th>Type</th>
<th>Request</th>
</tr>
</thead>
</table>
<script>
... on task change ...
... var task = $("#task").val(); ...
$('#user-request').DataTable({
'processing': true,
'serverSide': true,
'ajax': {
'type': 'POST',
'url': base_url+'user/get_user_request',
'data': {"task":task,"csrf_token":$("input[name=csrf_token]").val()}
}
})
</script>
Note : Task is a different group, example like Class 1 or Class 2, Orchard University or Harvard University
On my Controller :
$task = $this->input->post('task', TRUE);
$user_request = $this->model->all_user_request(task);
foreach ($user_request as $ur)
{
$arr = array();
$arr[] = $ur->username;
$arr[] = $ur->type;
$arr[] = $ur->request;
$data[] = $arr;
}
$output = array(
"data" => $data
);
if (COUNT($output) > 0)
{
echo json_encode($output);
}
On my Model :
public function all_user_request($task_id) {
$query = "SELECT * FROM user_request WHERE task_id = ?";
return $this->db->query($query, $task_id)->result();
}
Note : In model is actually using 2 INNER JOIN, I'm just simplifying the select only for asking here. (turning into denormalization table only in here).
I was trying to add draw, recordsTotal, recordsFiltered to $output in my controller just using numeric data. Example
$output = array(
"draw" => 5,
"recordsTotal" => 5,
"recordsFiltered" => 5,
"data" => $data
);
if (COUNT($output) > 0)
{
echo json_encode($output);
}
I was searching for the answer but, and I think the problem is here but I still have no idea where I must get the draw - recordsTotal - recordsFiltered data. I see on another answer from others, they use "draw" => $_POST['draw'], then I tried it, and it's do nothing.
So I'm trying that using numeric data, but the result is still same. I need some help with this. It's still print 200 rows of data in table.
Showing 0 to 0 of 0 entries (filtered from NaN total entries). Then the pagination is still print and after I click the page 2, it's doing nothing.
Datatables send everything you need - if you take a look in your console under network you'll see, that they use the ajax-get method to send those requests to the server
The GET Parameter are as follows
draw
columns
start
length
search
You can find the entire list here
which means - you've to adapt your model properly...
something like that should work
public function all_user_request($task_id)
{
$intStart = intval($this->input->get("start"));
$intLength = intval($this->input->get("length"));
$strSearch = (strlen($this->input->get("search")["value"]) >= 2) ? $this->input->get("search",true)["value"] : false;
$order = $this->input->get("order",true);
$this->setQuery($task_id,$strSearch);
$query = $this->db->get();
$this->recordsTotal = $query->num_rows();
$this->setQuery($task_id, $strSearch);
if ($intStart >= 0 && $intLength > 0)
{
$this->db->limit($intLength,$intStart);
}
$strOrderField = 'username';
$strDirection = "ASC";
if (is_array($order))
{
switch($order[0]['column'])
{
case 1:
$strOrderField = 'type';
break;
case 2:
$strOrderField = 'request';
break;
}
if (!empty($order[0]['dir'])) $strDirection = $order[0]['dir'];
}
$this->db->order_by($strOrderField,$strDirection);
$query = $this->db->get();
$arrData = $query->result();
return $arrData;
}
public function getRecordsTotal()
{
return $this->recordsTotal;
}
private function setQuery($task_id, $strSearch="")
{
$this->db
->select('*')
->from('user_request')
->where('task_id', $task_id);
if (!empty($strSearch))
{
$this->db->like('task_id', $strSearch);
}
}
and your controller
//controller
$task = $this->input->post('task', TRUE);
$user_request = $this->model->all_user_request($task);
$data = [];
foreach ($user_request as $ur)
{
$data[] = [
$ur->username,
$ur->type,
$ur->request
];
}
$arrCompiledData = [
'data' => $data,
'draw' => $this->input->get('draw'),
'recordsTotal' => $this->model->getRecordsTotal(),
'recordsFiltered' => $this->model->getRecordsTotal(),
];
$this->output
->set_content_type('application/json')
->set_output(json_encode($arrCompiledData));
Please keep in mind i just wrote this down - maybe there are some typos, but you should be able to understand how the serverside processing of a datatables request should work.
As long as you chose the server mode, you have to manage everything via the requests.
So, you have to dynamically create the values of the output array :
$output = array(
"draw" => $_POST['draw'],
"recordsTotal" => $this->my_model->get_total_records(),
"recordsFiltered" => $this->my_model->get_total_filtered(),
"data" => $this->my_model->all_user_request($id)
);
and the model functions
public function all_user_request($task_id) {
$query = "SELECT * FROM user_request WHERE task_id = ?"; // add limit $_POST['length'], $_POST['start'] to your request
return $this->db->query($query, $task_id)->result();
}
If you're using serverSide = true, you should provide your own filter count and total count. Also provide your own search function, ordering and etc. Use controller & model below for your reference.
Controller
$task = $this->input->post('task', TRUE);
$user_request = $this->model->all_user_request($task);
$output = array(
'draw' => $this->input->post('draw', TRUE),
'recordsTotal' => $user_request['recordsTotal'],
'recordsFiltered => $user_request['recordsFiltered'],
'data' => empty($user_request['data'])? array() : $user_request['data']
);
echo json_encode($output);
Model
public function all_user_request($task_id) {
$params = $this->input->post(null, TRUE);
$search_fields = array('username','type','request'); //change this into your table fields
$data = array();
$this->db->start_cache();
$this->db->select("username, type, request");
$this->db->from("user_request");
$this->db->where("task_id", $task_id);
if(!empty($params['search']['value'])){
$str = $params['search']['value'];
$this->db->group_start();
foreach($search_fields as $row){
$this->db->or_like($row, $str, 'BOTH');
}
$this->db->group_end();
}
$data['recordsTotal'] = $this->db->count_all_results();
$this->db->stop_cache();
$this->db->limit($params['length'], $params['start']);
$data['recordsFiltered'] = $this->db->count_all_results();
$query = $this->db->get();
$this->db->flush_cache();
foreach($query->result_array() as $row){
$data['data'][] = array_values($row);
}
return $data;
}
I have a class Pagination with a method that counts the total number of articles. When I instantiate the class, I explicitly type the sql query and give him the parameters. Here is an example:
$pagination = new Pagination(self::DATABASE_FORUM_TOPICS, $this->currentPage, self::TOPICS_IN_CATEGORY, [
'query' => 'SELECT COUNT(*) as count FROM ' . self::DATABASE_FORUM_TOPICS . ' WHERE title LIKE ?',
'params' => "%$keyWord%"
]);
The method that handles the query runs it and returns the result:
return $this->db->getRows($this->query['query'], [$this->query['params']]);
Everything works perfect, however, for this particular case (for searching articles) I want not only to count the results that match title but also by content, in other words I want to change to:
'SELECT COUNT(*) as count FROM ' . self::DATABASE_FORUM_TOPICS . ' WHERE title LIKE ? OR content LIKE ?'
But how do I pass the second parameter in 'params' => "%$keyWord%" ?
Edit:
Pagination class.
public function __construct(string $table, $currentPage = 1, $perPage, $query = [])
{
$this->db = Database::getInstance();
$this->currentPage = $currentPage;
$this->perPage = $perPage;
$this->table = $table;
$this->query = $query;
$getTotalRows = $this->countResultsFromTable();
$getTotalRows = $getTotalRows[0]->count;
$this->total = ceil($getTotalRows / $this->perPage);
}
public function countResultsFromTable()
{
if(empty($this->query))
{
return $this->db->getRows("SELECT COUNT(*) as count FROM $this->table");
}
else
{
return $this->db->getRows($this->query['query'], [$this->query['params']]);
}
}
Try the following: extend your call to
$pagination = new Pagination(self::DATABASE_FORUM_TOPICS, $this->currentPage, self::TOPICS_IN_CATEGORY, [
'query' => 'SELECT COUNT(*) as count FROM ' . self::DATABASE_FORUM_TOPICS . ' WHERE title LIKE ? AND content LIKE ?',
'title' => "%$keyWord%",
'content' => $CONTENT
]);
and the query evaluation to
return $this->db->getRows($this->query['query'],
[$this->query['title'], $this->query['content']]
);
If you don't want to change the Pagination class, append the content to the query before instantiating the Pagination:
$pagination = new Pagination(self::DATABASE_FORUM_TOPICS, $this->currentPage, self::TOPICS_IN_CATEGORY, [
'query' => 'SELECT COUNT(*) as count FROM ' . self::DATABASE_FORUM_TOPICS . ' WHERE title LIKE ? AND content LIKE "%' . your_escaping_function($content) . '%"',
'title' => "%$keyWord%"
]);
Can someone please guide me how I can fetch mysql row's value for "pk" to the $response variable to be able to allow the script to unfollow users automatically. I have already tried the script and it does unfollow when an pk id is provided but I want to automatically fetch it from mysql to be able to run it. Thank you for any help provided.
These are the methods I tried with no success:
$this->db->select('pk');
$this->model->from(INSTAGRAM_FOLLOW_TB);
$this->db->where("id = '11'");
$query1 = $this->db->get();
$result = $query1->result();
Main ID that only unfollow this ID- created by Mushfik Media,
$response = $i->unfollow($result);
I have also tried
$accounts = $this->model->fetch("*", INSTAGRAM_ACCOUNT_TB, "id = '11'");
$response = $i->unfollow($accounts->pk);
But didn't work. $NEED MYSQL DATA VALUE is where the value is supposed to be echoed but doesn't
case 'unfollow':
try {
$result = $i->getSelfUsersFollowing();
if(!empty($result) && $result->status == "ok" && !empty($result->users)){
$response = $i->unfollow($NEED MYSQL DATA VALUE);
$response = $response->status;
$CI =& get_instance();
$CI->load->model('Schedule_model', 'schedule_model');
$lang = $CI->db->insert(INSTAGRAM_FOLLOW_TB, array(
"pk" => $row->pk,
"name" => $row->username,
"type" => $data->schedule_type,
"uid" => $data->uid,
"account_id" => $data->account,
"account_name" => $data->name,
"created" => NOW
));
}
} catch (Exception $e){
$response = $e->getMessage();
}
break;
Maybe something like this to get your pk:
$query1 = $this->db->select('pk')
->from(INSTAGRAM_FOLLOW_TB)
->where('id', 11)
->get();
if( $query1->num_rows() == 1 ){
$row = $query1->row();
$response = $i->unfollow( $row->pk );
}
Regarding your information that you are trying to use $this when not in object context, because you are in a helper, you need to get the CI super object. So, if you were trying to use $this->db, you would do this:
$CI =& get_instance();
// Now you can use $CI->db
// and anything you would normally
// access via $this in a controller
// or model
OK, finally to show an example of how to order or limit a query:
$query1 = $this->db->select('pk')
->from(INSTAGRAM_FOLLOW_TB)
->where('id', 11)
->order_by('your_timestamp_field', 'ASC') // This would order by timestamp in ascending order
->limit(1) // This would limit to a single row
->get();
I build a custom query and tried use the default paginator, like this:
WodsController.php
$userId = $this->Auth->user('id');
$connection = ConnectionManager::get('default');
$result = $connection->execute("SELECT wods.id, wods.titulo , wods.dia , wods.tempo, wods.repeticoes ,userwods.user_id FROM wods
LEFT JOIN userwods ON userwods.wod_id = wods.id WHERE userwods.user_id is null or userwods.user_id=4 order by wods.dia desc limit 50")->fetchAll('assoc');
$results = array();
foreach ($result as $r) {
$entity = $this->Wods->newEntity($r);
array_push($results, $entity);
}
$wods = $this->paginate($results);
$this->set('_serialize', ['wods']);
I got this error "Unable to locate an object compatible with paginate".
Now I'm tryng implement custom query paginator, but it's not working.
I implemented paginate and paginateCount functions in the model.
Wods.php file:
public function paginate($conditions, $fields, $order, $limit, $page = 1, $recursive = null, $extra = array()) {
$recursive = -1;
$this->useTable = false;
$sql = '';
$sql .= "SELECT wods.id, wods.titulo , wods.dia , wods.tempo, wods.repeticoes ,userwods.user_id FROM wods LEFT JOIN userwods ON userwods.wod_id = wods.id WHERE userwods.user_id is null or userwods.user_id=4 order by wods.dia desc limit ";
// Adding LIMIT Clause
$sql .= (($page - 1) * $limit) . ', ' . $limit;
$results = $this->query($sql);
return $results;
}
public function paginateCount($conditions = null, $recursive = 0, $extra = array()) {
$sql = '';
$sql .= "SELECT wods.id, wods.titulo , wods.dia , wods.tempo, wods.repeticoes ,userwods.user_id FROM wods LEFT JOIN userwods ON userwods.wod_id = wods.id WHERE userwods.user_id is null or userwods.user_id=4 order by wods.dia desc";
$this->recursive = $recursive;
$results = $this->query($sql);
return count($results);
}
In the controller WodsController.php
public function index()
{
$this->Wods->recursive = 0;
$this->paginate = array('Wods'=>array('limit'=>10));
$this->set('wods', $this->paginate('Wods'));
}
But the custom paginator is not called, it continues calling the default paginate function. Why ?
Following dragmosh advise (thanks), I investigate CakePHP ORM custom queries builder.
In this solution I used find() function with specific options, after I called the default paginator:
$query = $this->Wods->find()
->select(['Wods.id', 'Wods.titulo','Wods.dia','Wods.rounds','Wods.tempo','Wods.repeticoes','Userwods.user_id'])
->join([
'table' => 'Userwods',
'alias' => 'Userwods',
'type' => 'LEFT',
'conditions' => 'Userwods.wod_id = Wods.id',
])
->where(function ($exp, $q) {
return $exp->isNull('Userwods.user_id');})
->orWhere(['Userwods.user_id' => 4])
->contain(['Userwods'])
->autoFields(true);
$wods = $this->paginate($query);
$this->set(compact('wods'));
$this->set('_serialize', ['wods']);
I'm trying to use custom query in Cake then paginate the results with the code below:
$query = $this->Petition->query($sql);
I tried:
$petitions = $this->paginate($query);
and it doesn't work. Is there a way we can do this?
OK I wasn't clear enough: I need to use variable array fetched from custom query on pagination so I can use this for pagination in the view. Is there an easy way of doing this?
Below is my code:
function index() {
if ($this->Session->read('Auth.User.group_id') != 1) {
$commune_id = $this->Session->read('Auth.User.commune_id');
$commune_id = $this->Petition->Commune->findbyId($commune_id);
$commune_id = $this->Petition->Commune->find('all',array('conditions' => array('group' => $commune_id['Commune']['group'])));
$count = count($commune_id);
$i=1;
$sql = "SELECT * FROM `petitions` WHERE `commune_id` = ";
foreach($commune_id as $commune_ids){
if($i==1){
$sql .= $commune_ids['Commune']['id'];
}else{
$sql .= " OR `commune_id` = ".$commune_ids['Commune']['id'];
}
/*if($i != $count){
$this->paginate = array(
'or' => array(
array('Petition.commune_id LIKE' => $commune_ids['Commune']['id'] . ","),
//array('Petition.commune_id LIKE' => "," . $commune_ids['Commune']['id'] . ",")
),
'limit' => 10
);
}*/
$i++;
}
$query = $this->Petition->query($sql);
}
$this->Petition->recursive = 0;
$petitions = $this->paginate();
$this->set('petitions', $petitions);
}
you seriously need to read the pagination part in the cake book:
function index() {
$conditions = array();
if ($this->Auth->user('group_id') != 1) {
$commune_id = $this->Petition->Commune->findById($this->Auth->user('commune_id'));
$conditions['Petition.id'] = $this->Petition->Commune->find('list',array(
'fields'=>array('id','id')
'conditions' => array('group' => $commune_id['Commune']['group'])
));
}
$this->Petition->recursive = 0;
$petitions = $this->paginate('Petition',$conditions);
$this->set('petitions', $petitions);
}
something like that.
this is not how pagination works
you need to fill $this->validate with your conditions etc
and then use $this->paginate() plainly
see
http://book.cakephp.org/view/1232/Controller-Setup
also note the chapter about the custom query part if it is really(!) necessary.