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%"
]);
Related
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!!
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've followed FOSComment's instruction to have multiple threads in one page. It's ok everything works. Just kidding, the world isn't that beautiful.
I'll try to explain my problem : When I submit my comment, i've got Integrity constraint violation due to the URL, I don't pass any Thread_id in my URL.
I found the piece of code in my controller which does that, but I've got no idea how to correct it. So, there's my controller :
public function indexAction(Request $request)
{
$stmt = $this->getDoctrine()->getEntityManager()
->getConnection()
->prepare('select ttrss_entries.id, title, content, body, thread_id '
. 'FROM ttrss_entries '
. 'LEFT JOIN ttrss_tags ON ttrss_entries.id = ttrss_tags.post_int_id '
. 'LEFT JOIN comment on comment.thread_id = ttrss_entries.id '
. 'WHERE ttrss_tags.tag_name = "politique" '
. 'GROUP BY ttrss_entries.id');
$stmt->execute();
$result = $stmt->fetchAll();
//Here my problem
$id = 'thread_id';
$thread = $this->container->get('fos_comment.manager.thread')->findThreadById($id);
if (null === $thread) {
$thread = $this->container->get('fos_comment.manager.thread')->createThread();
$thread->setId($id);
$thread->setPermalink($request->getUri());
$this->container->get('fos_comment.manager.thread')->saveThread($thread);
}
$comments = $this->container->get('fos_comment.manager.comment')->findCommentTreeByThread($thread);
return $this->render('AppBundle:Politique:index.html.twig', array(
'comments' => $comments,
'thread' => $thread,
'entities' => $result,
));
}
Here my view :
<div class="fos_comment_thread" data-thread-id="{{ thread.id }}">
{% include 'FOSCommentBundle:Thread:comments.html.twig' with {
'comments': comments,
'thread': thread
} %}
Thanks in advance for your help
PS : I'm a newbie with Symfony.
I want to fetch contents with multiple filters, right now there's only one.
For Example:
SELECT * FROM Table1 WHERE status=true AND category = 'Camera' AND
model = 'Samsung' AND type = 'New'
I want to create an array for it. But as I'm a newbie in this one not getting a lead.
function getAllRequests($filter){
if(empty($filter)){
$addfilter = '';
}else{
$addfilter = 'AND cat_id=' . $filter;
}
}
$sql = 'SELECT * FROM Table1 WHERE status=true' . $filter;
Any help will be appreciated.
This will get you closer to the solution, though it will not replace the cat_id in the query, which will certainly be wrong - though impossible to do too much more without the array structure:
function getAllRequests($filter)
{
$addfilter="";
if(!empty($filter))
{
foreach($filter as $val)
{
$addfilter. = ' AND cat_id=' . $val .'\'';
}
}
return $addFilter;
}
$myFilters=getAllRequests($filter);
$sql = 'SELECT * FROM Table1 WHERE status=true' . $myFilters;
On the other hand, if your array is strucutred in a way like this:
array{ category => camera, model => samsung); // etc
you could use the following:
function getAllRequests($filter)
{
$addfilter="";
if(!empty($filter))
{
foreach($filter as $key => $val)
{
$addfilter. = " AND `$key` = '$val'";
}
}
return $addFilter;
}
$myFilters=getAllRequests($filter);
$sql = 'SELECT * FROM Table1 WHERE status=true' . $myFilters;
Edit: You can loop through all the filters in the following manner:
function getAllRequests()
{
$addfilter="";
if(!empty($_REQUEST))
{
foreach($_REQUEST as $key => $val)
{
$addfilter. = " AND `$key` = '$val'";
}
}
return $addFilter;
}
$myFilters=getAllRequests();
$sql = 'SELECT * FROM Table1 WHERE status=true' . $myFilters;
You don't need to pass the $_REQUEST (which will work for both GET and POST) as it already a superglobal.
function getAllRequests($filter){
if(empty($filter)){
$addfilter = '';
}else{
$addfilter = 'AND cat_id=' . $filter;
}
}
$sql = 'SELECT * FROM Table1 WHERE status=true' . $addfilter;
You can use another approach, which is using optional parameters and it will make your WHERE clause dynamic as you want. In this approach you pass all parameters' values directly to the sql query which should look like so:
SELECT *
FROM Table1
WHERE 1 = 1
AND (#status IS NULL OR status = #statusParam)
AND (#category IS NULL OR category = #categoryParam)
AND (#model IS NULL OR model = #modelParam)
AND (#type IS NULL OR type = #typeParam)
Then If any of the parameters #statusParam, #categoryParam, #modelParam or #typeParam passed to the query with NULL values, then the comparison with the column holding that value will be ignored. I used the predicate 1 = 1, in case all the values passed to the query with all NULL values in the case all the WHERE clause will be ignored as it won't presented, since WHERE 1 = 1 always true and it will be like SELECT * FROM Table1.
use this
function getAllRequests($filter){
if(empty($filter)){
$addfilter = '';
}else{
$addfilter .= 'AND cat_id=' . $filter;
}
return $addfilter;
}
$sql = 'SELECT * FROM Table1 WHERE status=true' . getAllRequests($filter);
When you are sending array make sure it has indexes
$conditions = array('category' => 'Camera', 'model' => 'Samsung' , 'type' => 'New')
Now loop through it. in your else condition
foreach($conditions as $key =>$value){
$addfilter .= 'AND ' . $key . ' = ' . $value;
}
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.